1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //See www.gnu.org/software/bc/manual/bc.html
118 //usage:#define bc_trivial_usage
119 //usage: "[-sqli] FILE..."
121 //usage:#define bc_full_usage "\n"
122 //usage: "\nArbitrary precision calculator"
124 //usage: "\n -i Interactive"
125 //usage: "\n -l Load standard math library"
126 //usage: "\n -s Be POSIX compatible"
127 //usage: "\n -q Quiet"
128 //usage: "\n -w Warn if extensions are used"
129 ///////: "\n -v Version"
131 //usage:#define bc_example_usage
132 //usage: "3 + 4.129\n"
133 //usage: "1903 - 2893\n"
134 //usage: "-129 * 213.28935\n"
135 //usage: "12 / -1932\n"
137 //usage: "34 ^ 189\n"
138 //usage: "scale = 13\n"
139 //usage: "ibase = 2\n"
140 //usage: "obase = A\n"
142 //usage:#define dc_trivial_usage
143 //usage: "EXPRESSION..."
145 //usage:#define dc_full_usage "\n\n"
146 //usage: "Tiny RPN calculator. Operations:\n"
147 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148 //usage: "modular exponentiation,\n"
149 //usage: "p - print top of the stack (without popping),\n"
150 //usage: "f - print entire stack,\n"
151 //usage: "k - pop the value and set the precision.\n"
152 //usage: "i - pop the value and set input radix.\n"
153 //usage: "o - pop the value and set output radix.\n"
154 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
156 //usage:#define dc_example_usage
157 //usage: "$ dc 2 2 + p\n"
159 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
161 //usage: "$ dc 0 1 and p\n"
163 //usage: "$ dc 0 1 or p\n"
165 //usage: "$ echo 72 9 div 8 mul p | dc\n"
170 typedef enum BcStatus {
171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
176 #define BC_VEC_INVALID_IDX ((size_t) -1)
177 #define BC_VEC_START_CAP (1 << 5)
179 typedef void (*BcVecFree)(void *);
181 typedef struct BcVec {
189 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
190 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
192 typedef signed char BcDig;
194 typedef struct BcNum {
202 #define BC_NUM_MIN_BASE ((unsigned long) 2)
203 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
204 #define BC_NUM_DEF_SIZE (16)
205 #define BC_NUM_PRINT_WIDTH (69)
207 #define BC_NUM_KARATSUBA_LEN (32)
209 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
210 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
211 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
212 #define BC_NUM_AREQ(a, b) \
213 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
214 #define BC_NUM_MREQ(a, b, scale) \
215 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
217 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
218 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
220 static void bc_num_init(BcNum *n, size_t req);
221 static void bc_num_expand(BcNum *n, size_t req);
222 static void bc_num_copy(BcNum *d, BcNum *s);
223 static void bc_num_free(void *num);
225 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
226 static void bc_num_ulong2num(BcNum *n, unsigned long val);
228 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
229 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
230 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
235 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
238 typedef enum BcInst {
268 BC_INST_ASSIGN_POWER,
269 BC_INST_ASSIGN_MULTIPLY,
270 BC_INST_ASSIGN_DIVIDE,
271 BC_INST_ASSIGN_MODULUS,
273 BC_INST_ASSIGN_MINUS,
319 BC_INST_PRINT_STREAM,
334 BC_INST_INVALID = -1,
339 typedef struct BcId {
344 typedef struct BcFunc {
351 typedef enum BcResultType {
356 BC_RESULT_ARRAY_ELEM,
365 // These are between to calculate ibase, obase, and last from instructions.
373 typedef union BcResultData {
379 typedef struct BcResult {
384 typedef struct BcInstPtr {
390 static void bc_array_expand(BcVec *a, size_t len);
391 static int bc_id_cmp(const void *e1, const void *e2);
393 // BC_LEX_NEG is not used in lexing; it is only for parsing.
394 typedef enum BcLexType {
422 BC_LEX_OP_ASSIGN_POWER,
423 BC_LEX_OP_ASSIGN_MULTIPLY,
424 BC_LEX_OP_ASSIGN_DIVIDE,
425 BC_LEX_OP_ASSIGN_MODULUS,
426 BC_LEX_OP_ASSIGN_PLUS,
427 BC_LEX_OP_ASSIGN_MINUS,
448 BC_LEX_KEY_1st_keyword,
449 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
456 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
457 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
459 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
462 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
500 // must match order of BC_LEX_KEY_foo etc above
502 struct BcLexKeyword {
505 #define BC_LEX_KW_ENTRY(a, b, c) \
506 { .name8 = a /*, .len = b, .posix = c*/ }
507 static const struct BcLexKeyword bc_lex_kws[20] = {
508 BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
509 BC_LEX_KW_ENTRY("break" , 5, 1), // 1
510 BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
511 BC_LEX_KW_ENTRY("define" , 6, 1), // 3
513 BC_LEX_KW_ENTRY("else" , 4, 0), // 4
514 BC_LEX_KW_ENTRY("for" , 3, 1), // 5
515 BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
516 BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
518 BC_LEX_KW_ENTRY("if" , 2, 1), // 8
519 BC_LEX_KW_ENTRY("last" , 4, 0), // 9
520 BC_LEX_KW_ENTRY("length" , 6, 1), // 10
521 BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
523 BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
524 BC_LEX_KW_ENTRY("print" , 5, 0), // 13
525 BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
526 BC_LEX_KW_ENTRY("read" , 4, 0), // 15
528 BC_LEX_KW_ENTRY("return" , 6, 1), // 16
529 BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
530 BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
531 BC_LEX_KW_ENTRY("while" , 5, 1), // 19
563 typedef BcStatus (*BcLexNext)(struct BcLex *);
565 typedef struct BcLex {
583 #define BC_PARSE_STREND ((char) UCHAR_MAX)
585 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
586 #define bc_parse_updateFunc(p, f) \
587 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
589 #define BC_PARSE_REL (1 << 0)
590 #define BC_PARSE_PRINT (1 << 1)
591 #define BC_PARSE_NOCALL (1 << 2)
592 #define BC_PARSE_NOREAD (1 << 3)
593 #define BC_PARSE_ARRAY (1 << 4)
595 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
596 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
598 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
599 #define BC_PARSE_FUNC_INNER(parse) \
600 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
602 #define BC_PARSE_FLAG_FUNC (1 << 1)
603 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
605 #define BC_PARSE_FLAG_BODY (1 << 2)
606 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
608 #define BC_PARSE_FLAG_LOOP (1 << 3)
609 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
611 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
612 #define BC_PARSE_LOOP_INNER(parse) \
613 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
615 #define BC_PARSE_FLAG_IF (1 << 5)
616 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
618 #define BC_PARSE_FLAG_ELSE (1 << 6)
619 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
621 #define BC_PARSE_FLAG_IF_END (1 << 7)
622 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
624 #define BC_PARSE_CAN_EXEC(parse) \
625 (!(BC_PARSE_TOP_FLAG(parse) & \
626 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
627 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
628 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
630 typedef struct BcOp {
635 typedef struct BcParseNext {
640 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
641 #define BC_PARSE_NEXT(a, ...) \
643 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
650 typedef BcStatus (*BcParseParse)(struct BcParse *);
652 typedef struct BcParse {
675 static BcStatus bc_lex_token(BcLex *l);
677 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
678 #define BC_PARSE_LEAF(p, rparen) \
679 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
680 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
682 // We can calculate the conversion between tokens and exprs by subtracting the
683 // position of the first operator in the lex enum and adding the position of the
684 // first in the expr enum. Note: This only works for binary operators.
685 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
687 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
693 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
695 static BcStatus dc_lex_token(BcLex *l);
697 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
701 typedef struct BcProgram {
742 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
744 #define BC_PROG_MAIN (0)
745 #define BC_PROG_READ (1)
748 #define BC_PROG_REQ_FUNCS (2)
751 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
752 #define BC_PROG_NUM(r, n) \
753 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
755 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
757 static void bc_program_addFunc(char *name, size_t *idx);
758 static void bc_program_reset(void);
760 #define BC_FLAG_X (1 << 0)
761 #define BC_FLAG_W (1 << 1)
762 #define BC_FLAG_V (1 << 2)
763 #define BC_FLAG_S (1 << 3)
764 #define BC_FLAG_Q (1 << 4)
765 #define BC_FLAG_L (1 << 5)
766 #define BC_FLAG_I (1 << 6)
768 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
769 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
771 #define BC_MAX_OBASE ((unsigned) 999)
772 #define BC_MAX_DIM ((unsigned) INT_MAX)
773 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
774 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
775 #define BC_MAX_NAME BC_MAX_STRING
776 #define BC_MAX_NUM BC_MAX_STRING
777 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
778 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
789 // For error messages. Can be set to current parsed line,
790 // or [TODO] to current executing line (can be before last parsed one)
797 #define G (*ptr_to_globals)
798 #define INIT_G() do { \
799 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
801 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
802 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
803 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
804 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
807 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
809 static void bc_vm_info(void);
813 // This is an array that corresponds to token types. An entry is
814 // true if the token is valid in an expression, false otherwise.
815 static const bool bc_parse_exprs[] = {
816 false, false, true, true, true, true, true, true, true, true, true, true,
817 true, true, true, true, true, true, true, true, true, true, true, true,
818 true, true, true, false, false, true, true, false, false, false, false,
819 false, false, false, true, true, false, false, false, false, false, false,
820 false, true, false, true, true, true, true, false, false, true, false, true,
824 // This is an array of data for operators that correspond to token types.
825 static const BcOp bc_parse_ops[] = {
826 { 0, false }, { 0, false },
829 { 3, true }, { 3, true }, { 3, true },
830 { 4, true }, { 4, true },
831 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
833 { 7, true }, { 7, true },
834 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
835 { 5, false }, { 5, false },
838 // These identify what tokens can come after expressions in certain cases.
839 static const BcParseNext bc_parse_next_expr =
840 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
841 static const BcParseNext bc_parse_next_param =
842 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
843 static const BcParseNext bc_parse_next_print =
844 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
845 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
846 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
847 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
848 static const BcParseNext bc_parse_next_read =
849 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
853 static const BcLexType dc_lex_regs[] = {
854 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
855 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
856 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
860 static const BcLexType dc_lex_tokens[] = {
861 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
862 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
863 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
864 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
865 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID,
867 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
868 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
869 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
870 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
871 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
872 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
873 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
874 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
875 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
876 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
877 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
878 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
879 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
880 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
881 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
882 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
883 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
884 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
888 static const BcInst dc_parse_insts[] = {
889 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
890 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
891 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID,
894 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
895 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
896 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
897 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
899 BC_INST_INVALID, BC_INST_INVALID,
900 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
901 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
903 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
904 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
905 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
906 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
908 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
909 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
910 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
911 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
915 static const BcNumBinaryOp bc_program_ops[] = {
916 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
919 static void fflush_and_check(void)
922 if (ferror(stdout) || ferror(stderr))
923 bb_perror_msg_and_die("output error");
926 static void quit(void) NORETURN;
927 static void quit(void)
930 bb_perror_msg_and_die("input error");
935 static void bc_verror_msg(const char *fmt, va_list p)
937 const char *sv = sv; /* for compiler */
940 applet_name = xasprintf("%s: %s:%u", applet_name, G.prog.file, G.err_line);
942 bb_verror_msg(fmt, p, NULL);
944 free((char*)applet_name);
949 static NOINLINE int bc_error_fmt(const char *fmt, ...)
954 bc_verror_msg(fmt, p);
959 return BC_STATUS_FAILURE;
962 static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
966 // Are non-POSIX constructs totally ok?
967 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
968 return BC_STATUS_SUCCESS; // yes
971 bc_verror_msg(fmt, p);
974 // Do we treat non-POSIX constructs as errors?
975 if (!(option_mask32 & BC_FLAG_S))
976 return BC_STATUS_SUCCESS; // no, it's a warning
979 return BC_STATUS_FAILURE;
982 // We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
983 // This idiom begs for tail-call optimization, but for it to work,
984 // function must not have calller-cleaned parameters on stack.
985 // Unfortunately, vararg functions do exactly that on most arches.
986 // Thus, these shims for the cases when we have no PARAMS:
987 static int bc_error(const char *msg)
989 return bc_error_fmt("%s", msg);
991 static int bc_posix_error(const char *msg)
993 return bc_posix_error_fmt("%s", msg);
995 static int bc_POSIX_does_not_allow(const char *msg)
997 return bc_posix_error_fmt("%s%s", "POSIX does not allow ", msg);
999 static int bc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
1001 return bc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; the following is bad:", msg);
1003 static int bc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
1005 return bc_posix_error_fmt("%san empty %s expression in a for loop", "POSIX does not allow ", msg);
1007 static int bc_error_bad_character(char c)
1009 return bc_error_fmt("bad character '%c'", c);
1011 static int bc_error_bad_expression(void)
1013 return bc_error("bad expression");
1015 static int bc_error_bad_token(void)
1017 return bc_error("bad token");
1019 static int bc_error_stack_has_too_few_elements(void)
1021 return bc_error("stack has too few elements");
1023 static int bc_error_variable_is_wrong_type(void)
1025 return bc_error("variable is wrong type");
1027 static int bc_error_nested_read_call(void)
1029 return bc_error("read() call inside of a read() call");
1032 static void bc_vec_grow(BcVec *v, size_t n)
1034 size_t cap = v->cap * 2;
1035 while (cap < v->len + n) cap *= 2;
1036 v->v = xrealloc(v->v, v->size * cap);
1040 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1043 v->cap = BC_VEC_START_CAP;
1046 v->v = xmalloc(esize * BC_VEC_START_CAP);
1049 static void bc_char_vec_init(BcVec *v)
1051 bc_vec_init(v, sizeof(char), NULL);
1054 static void bc_vec_expand(BcVec *v, size_t req)
1057 v->v = xrealloc(v->v, v->size * req);
1062 static void bc_vec_npop(BcVec *v, size_t n)
1067 size_t len = v->len - n;
1068 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1072 static void bc_vec_pop_all(BcVec *v)
1074 bc_vec_npop(v, v->len);
1077 static void bc_vec_push(BcVec *v, const void *data)
1079 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1080 memmove(v->v + (v->size * v->len), data, v->size);
1084 static void bc_vec_pushByte(BcVec *v, char data)
1086 bc_vec_push(v, &data);
1089 static void bc_vec_pushZeroByte(BcVec *v)
1091 //bc_vec_pushByte(v, '\0');
1093 bc_vec_push(v, &const_int_0);
1096 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1099 bc_vec_push(v, data);
1104 if (v->len == v->cap) bc_vec_grow(v, 1);
1106 ptr = v->v + v->size * idx;
1108 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1109 memmove(ptr, data, v->size);
1113 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1116 bc_vec_expand(v, len + 1);
1117 memcpy(v->v, str, len);
1120 bc_vec_pushZeroByte(v);
1123 static void bc_vec_concat(BcVec *v, const char *str)
1127 if (v->len == 0) bc_vec_pushZeroByte(v);
1129 len = v->len + strlen(str);
1131 if (v->cap < len) bc_vec_grow(v, len - v->len);
1137 static void *bc_vec_item(const BcVec *v, size_t idx)
1139 return v->v + v->size * idx;
1142 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1144 return v->v + v->size * (v->len - idx - 1);
1147 static void bc_vec_free(void *vec)
1149 BcVec *v = (BcVec *) vec;
1154 static size_t bc_map_find(const BcVec *v, const void *ptr)
1156 size_t low = 0, high = v->len;
1158 while (low < high) {
1160 size_t mid = (low + high) / 2;
1161 BcId *id = bc_vec_item(v, mid);
1162 int result = bc_id_cmp(ptr, id);
1166 else if (result < 0)
1175 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1177 size_t n = *i = bc_map_find(v, ptr);
1180 bc_vec_push(v, ptr);
1181 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1182 return 0; // "was not inserted"
1184 bc_vec_pushAt(v, ptr, n);
1185 return 1; // "was inserted"
1188 static size_t bc_map_index(const BcVec *v, const void *ptr)
1190 size_t i = bc_map_find(v, ptr);
1191 if (i >= v->len) return BC_VEC_INVALID_IDX;
1192 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1195 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1203 bc_vec_pop_all(vec);
1206 #if ENABLE_FEATURE_BC_SIGNALS
1207 if (bb_got_signal) { // ^C was pressed
1209 bb_got_signal = 0; // resets G_interrupt to zero
1211 ? "\ninterrupt (type \"quit\" to exit)\n"
1212 : "\ninterrupt (type \"q\" to exit)\n"
1216 if (G.ttyin && !G_posix)
1217 fputs(prompt, stderr);
1219 #if ENABLE_FEATURE_BC_SIGNALS
1225 #if ENABLE_FEATURE_BC_SIGNALS
1226 // Both conditions appear simultaneously, check both just in case
1227 if (errno == EINTR || bb_got_signal) {
1234 quit(); // this emits error message
1236 // Note: EOF does not append '\n', therefore:
1237 // printf 'print 123\n' | bc - works
1238 // printf 'print 123' | bc - fails (syntax error)
1242 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1245 // Bad chars on this line, ignore entire line
1246 bc_error_fmt("illegal character 0x%02x", i);
1249 bc_vec_pushByte(vec, (char)i);
1250 } while (i != '\n');
1251 } while (bad_chars);
1253 bc_vec_pushZeroByte(vec);
1255 return BC_STATUS_SUCCESS;
1258 static char* bc_read_file(const char *path)
1261 size_t size = ((size_t) -1);
1264 buf = xmalloc_open_read_close(path, &size);
1266 for (i = 0; i < size; ++i) {
1268 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1280 static void bc_args(int argc, char **argv)
1286 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1287 opts = getopt32long(argv, "xwvsqli",
1288 "extended-register\0" No_argument "x"
1289 "warn\0" No_argument "w"
1290 "version\0" No_argument "v"
1291 "standard\0" No_argument "s"
1292 "quiet\0" No_argument "q"
1293 "mathlib\0" No_argument "l"
1294 "interactive\0" No_argument "i"
1297 opts = getopt32(argv, "xwvsqli");
1299 if (getenv("POSIXLY_CORRECT"))
1300 option_mask32 |= BC_FLAG_S;
1302 if (opts & BC_FLAG_V) bc_vm_info();
1303 // should not be necessary, getopt32() handles this??
1304 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1306 for (i = optind; i < argc; ++i)
1307 bc_vec_push(&G.files, argv + i);
1310 static void bc_num_setToZero(BcNum *n, size_t scale)
1317 static void bc_num_zero(BcNum *n)
1319 bc_num_setToZero(n, 0);
1322 static void bc_num_one(BcNum *n)
1324 bc_num_setToZero(n, 0);
1329 static void bc_num_ten(BcNum *n)
1331 bc_num_setToZero(n, 0);
1337 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1341 for (i = 0; i < len; ++i) {
1342 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1349 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1353 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1354 return BC_NUM_NEG(i + 1, c < 0);
1357 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1359 size_t i, min, a_int, b_int, diff;
1360 BcDig *max_num, *min_num;
1361 bool a_max, neg = false;
1364 if (a == b) return 0;
1365 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1366 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1376 a_int = BC_NUM_INT(a);
1377 b_int = BC_NUM_INT(b);
1379 a_max = (a->rdx > b->rdx);
1381 if (a_int != 0) return (ssize_t) a_int;
1385 diff = a->rdx - b->rdx;
1386 max_num = a->num + diff;
1391 diff = b->rdx - a->rdx;
1392 max_num = b->num + diff;
1396 cmp = bc_num_compare(max_num, min_num, b_int + min);
1397 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1399 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1400 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1406 static void bc_num_truncate(BcNum *n, size_t places)
1408 if (places == 0) return;
1414 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1418 static void bc_num_extend(BcNum *n, size_t places)
1420 size_t len = n->len + places;
1424 if (n->cap < len) bc_num_expand(n, len);
1426 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1427 memset(n->num, 0, sizeof(BcDig) * places);
1434 static void bc_num_clean(BcNum *n)
1436 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1439 else if (n->len < n->rdx)
1443 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1446 bc_num_extend(n, scale - n->rdx);
1448 bc_num_truncate(n, n->rdx - scale);
1451 if (n->len != 0) n->neg = !neg1 != !neg2;
1454 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1459 b->len = n->len - idx;
1461 a->rdx = b->rdx = 0;
1463 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1464 memcpy(a->num, n->num, idx * sizeof(BcDig));
1475 static BcStatus bc_num_shift(BcNum *n, size_t places)
1477 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1478 if (places + n->len > BC_MAX_NUM)
1479 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1481 if (n->rdx >= places)
1484 bc_num_extend(n, places - n->rdx);
1490 return BC_STATUS_SUCCESS;
1493 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1502 return bc_num_div(&one, a, b, scale);
1505 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1507 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1508 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1511 // Because this function doesn't need to use scale (per the bc spec),
1512 // I am hijacking it to say whether it's doing an add or a subtract.
1516 if (sub && c->len) c->neg = !c->neg;
1517 return BC_STATUS_SUCCESS;
1519 else if (b->len == 0) {
1521 return BC_STATUS_SUCCESS;
1525 c->rdx = BC_MAX(a->rdx, b->rdx);
1526 min_rdx = BC_MIN(a->rdx, b->rdx);
1529 if (a->rdx > b->rdx) {
1530 diff = a->rdx - b->rdx;
1532 ptr_a = a->num + diff;
1536 diff = b->rdx - a->rdx;
1539 ptr_b = b->num + diff;
1542 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1545 a_int = BC_NUM_INT(a);
1546 b_int = BC_NUM_INT(b);
1548 if (a_int > b_int) {
1559 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1560 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1562 ptr_c[i] = (BcDig)(in % 10);
1565 for (; i < max + min_rdx; ++i, ++c->len) {
1566 in = ((int) ptr[i]) + carry;
1568 ptr_c[i] = (BcDig)(in % 10);
1571 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1573 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1576 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1579 BcNum *minuend, *subtrahend;
1581 bool aneg, bneg, neg;
1583 // Because this function doesn't need to use scale (per the bc spec),
1584 // I am hijacking it to say whether it's doing an add or a subtract.
1588 if (sub && c->len) c->neg = !c->neg;
1589 return BC_STATUS_SUCCESS;
1591 else if (b->len == 0) {
1593 return BC_STATUS_SUCCESS;
1598 a->neg = b->neg = false;
1600 cmp = bc_num_cmp(a, b);
1606 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1607 return BC_STATUS_SUCCESS;
1616 if (sub) neg = !neg;
1621 bc_num_copy(c, minuend);
1624 if (c->rdx < subtrahend->rdx) {
1625 bc_num_extend(c, subtrahend->rdx - c->rdx);
1629 start = c->rdx - subtrahend->rdx;
1631 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1635 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1638 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1643 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1644 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1645 bool aone = BC_NUM_ONE(a);
1647 if (a->len == 0 || b->len == 0) {
1649 return BC_STATUS_SUCCESS;
1651 else if (aone || BC_NUM_ONE(b)) {
1652 bc_num_copy(c, aone ? b : a);
1653 return BC_STATUS_SUCCESS;
1656 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1657 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1659 bc_num_expand(c, a->len + b->len + 1);
1661 memset(c->num, 0, sizeof(BcDig) * c->cap);
1662 c->len = carry = len = 0;
1664 for (i = 0; i < b->len; ++i) {
1666 for (j = 0; j < a->len; ++j) {
1667 int in = (int) c->num[i + j];
1668 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1670 c->num[i + j] = (BcDig)(in % 10);
1673 c->num[i + j] += (BcDig) carry;
1674 len = BC_MAX(len, i + j + !!carry);
1680 return BC_STATUS_SUCCESS;
1683 bc_num_init(&l1, max);
1684 bc_num_init(&h1, max);
1685 bc_num_init(&l2, max);
1686 bc_num_init(&h2, max);
1687 bc_num_init(&m1, max);
1688 bc_num_init(&m2, max);
1689 bc_num_init(&z0, max);
1690 bc_num_init(&z1, max);
1691 bc_num_init(&z2, max);
1692 bc_num_init(&temp, max + max);
1694 bc_num_split(a, max2, &l1, &h1);
1695 bc_num_split(b, max2, &l2, &h2);
1697 s = bc_num_add(&h1, &l1, &m1, 0);
1699 s = bc_num_add(&h2, &l2, &m2, 0);
1702 s = bc_num_k(&h1, &h2, &z0);
1704 s = bc_num_k(&m1, &m2, &z1);
1706 s = bc_num_k(&l1, &l2, &z2);
1709 s = bc_num_sub(&z1, &z0, &temp, 0);
1711 s = bc_num_sub(&temp, &z2, &z1, 0);
1714 s = bc_num_shift(&z0, max2 * 2);
1716 s = bc_num_shift(&z1, max2);
1718 s = bc_num_add(&z0, &z1, &temp, 0);
1720 s = bc_num_add(&temp, &z2, c, 0);
1736 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1740 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1742 scale = BC_MAX(scale, a->rdx);
1743 scale = BC_MAX(scale, b->rdx);
1744 scale = BC_MIN(a->rdx + b->rdx, scale);
1745 maxrdx = BC_MAX(maxrdx, scale);
1747 bc_num_init(&cpa, a->len);
1748 bc_num_init(&cpb, b->len);
1750 bc_num_copy(&cpa, a);
1751 bc_num_copy(&cpb, b);
1752 cpa.neg = cpb.neg = false;
1754 s = bc_num_shift(&cpa, maxrdx);
1756 s = bc_num_shift(&cpb, maxrdx);
1758 s = bc_num_k(&cpa, &cpb, c);
1762 bc_num_expand(c, c->len + maxrdx);
1764 if (c->len < maxrdx) {
1765 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1770 bc_num_retireMul(c, scale, a->neg, b->neg);
1778 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1780 BcStatus s = BC_STATUS_SUCCESS;
1787 return bc_error("divide by zero");
1788 else if (a->len == 0) {
1789 bc_num_setToZero(c, scale);
1790 return BC_STATUS_SUCCESS;
1792 else if (BC_NUM_ONE(b)) {
1794 bc_num_retireMul(c, scale, a->neg, b->neg);
1795 return BC_STATUS_SUCCESS;
1798 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1799 bc_num_copy(&cp, a);
1803 bc_num_expand(&cp, len + 2);
1804 bc_num_extend(&cp, len - cp.len);
1807 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1809 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1811 if (b->rdx == b->len) {
1812 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1816 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1818 // We want an extra zero in front to make things simpler.
1819 cp.num[cp.len++] = 0;
1822 bc_num_expand(c, cp.len);
1825 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1830 for (i = end - 1; !s && i < end; --i) {
1832 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1833 bc_num_subArrays(n, p, len);
1837 bc_num_retireMul(c, scale, a->neg, b->neg);
1840 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1843 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1844 BcNum *restrict d, size_t scale, size_t ts)
1851 return bc_error("divide by zero");
1854 bc_num_setToZero(d, ts);
1855 return BC_STATUS_SUCCESS;
1858 bc_num_init(&temp, d->cap);
1859 bc_num_d(a, b, c, scale);
1861 if (scale != 0) scale = ts;
1863 s = bc_num_m(c, b, &temp, scale);
1865 s = bc_num_sub(a, &temp, d, scale);
1868 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1871 bc_num_retireMul(d, ts, a->neg, b->neg);
1879 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1883 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1885 bc_num_init(&c1, len);
1886 s = bc_num_r(a, b, &c1, c, scale, ts);
1892 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1894 BcStatus s = BC_STATUS_SUCCESS;
1897 size_t i, powrdx, resrdx;
1900 if (b->rdx) return bc_error("non integer number");
1904 return BC_STATUS_SUCCESS;
1906 else if (a->len == 0) {
1907 bc_num_setToZero(c, scale);
1908 return BC_STATUS_SUCCESS;
1910 else if (BC_NUM_ONE(b)) {
1914 s = bc_num_inv(a, c, scale);
1921 s = bc_num_ulong(b, &pow);
1924 bc_num_init(©, a->len);
1925 bc_num_copy(©, a);
1927 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1931 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1933 s = bc_num_mul(©, ©, ©, powrdx);
1935 // It is too slow to handle ^C only after entire "2^1000000" completes
1937 s = BC_STATUS_FAILURE;
1942 bc_num_copy(c, ©);
1944 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1947 s = bc_num_mul(©, ©, ©, powrdx);
1952 s = bc_num_mul(c, ©, c, resrdx);
1955 // It is too slow to handle ^C only after entire "2^1000000" completes
1957 s = BC_STATUS_FAILURE;
1963 s = bc_num_inv(c, c, scale);
1967 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1969 // We can't use bc_num_clean() here.
1970 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1971 if (zero) bc_num_setToZero(c, scale);
1978 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1979 BcNumBinaryOp op, size_t req)
1982 BcNum num2, *ptr_a, *ptr_b;
1987 memcpy(ptr_a, c, sizeof(BcNum));
1996 memcpy(ptr_b, c, sizeof(BcNum));
2004 bc_num_init(c, req);
2006 bc_num_expand(c, req);
2008 s = op(ptr_a, ptr_b, c, scale);
2010 if (init) bc_num_free(&num2);
2015 static bool bc_num_strValid(const char *val, size_t base)
2018 bool small, radix = false;
2019 size_t i, len = strlen(val);
2021 if (!len) return true;
2024 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2026 for (i = 0; i < len; ++i) {
2032 if (radix) return false;
2038 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2045 static void bc_num_parseDecimal(BcNum *n, const char *val)
2051 for (i = 0; val[i] == '0'; ++i);
2058 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2059 bc_num_expand(n, len);
2062 ptr = strchr(val, '.');
2066 n->rdx = (size_t)((val + len) - (ptr + 1));
2069 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2070 n->num[n->len] = val[i] - '0';
2074 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2077 BcNum temp, mult, result;
2081 size_t i, digits, len = strlen(val);
2085 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2088 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2089 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2091 for (i = 0; i < len; ++i) {
2094 if (c == '.') break;
2096 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2098 s = bc_num_mul(n, base, &mult, 0);
2099 if (s) goto int_err;
2100 bc_num_ulong2num(&temp, v);
2101 s = bc_num_add(&mult, &temp, n, 0);
2102 if (s) goto int_err;
2107 if (c == 0) goto int_err;
2110 bc_num_init(&result, base->len);
2111 bc_num_zero(&result);
2114 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2119 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2121 s = bc_num_mul(&result, base, &result, 0);
2123 bc_num_ulong2num(&temp, v);
2124 s = bc_num_add(&result, &temp, &result, 0);
2126 s = bc_num_mul(&mult, base, &mult, 0);
2130 s = bc_num_div(&result, &mult, &result, digits);
2132 s = bc_num_add(n, &result, n, digits);
2136 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2142 bc_num_free(&result);
2148 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2150 if (*nchars == line_len - 1) {
2158 static void bc_num_printChar(size_t num, size_t width, bool radix,
2159 size_t *nchars, size_t line_len)
2161 (void) radix, (void) line_len;
2162 bb_putchar((char) num);
2163 *nchars = *nchars + width;
2167 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2168 size_t *nchars, size_t line_len)
2172 bc_num_printNewline(nchars, line_len);
2173 bb_putchar(radix ? '.' : ' ');
2176 bc_num_printNewline(nchars, line_len);
2177 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2180 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2182 bc_num_printNewline(nchars, line_len);
2185 bb_putchar(((char) dig) + '0');
2189 static void bc_num_printHex(size_t num, size_t width, bool radix,
2190 size_t *nchars, size_t line_len)
2193 bc_num_printNewline(nchars, line_len);
2198 bc_num_printNewline(nchars, line_len);
2199 bb_putchar(bb_hexdigits_upcase[num]);
2200 *nchars = *nchars + width;
2203 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2205 size_t i, rdx = n->rdx - 1;
2207 if (n->neg) bb_putchar('-');
2208 (*nchars) += n->neg;
2210 for (i = n->len - 1; i < n->len; --i)
2211 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2214 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2215 size_t *nchars, size_t len, BcNumDigitOp print)
2219 BcNum intp, fracp, digit, frac_len;
2220 unsigned long dig, *ptr;
2225 print(0, width, false, nchars, len);
2226 return BC_STATUS_SUCCESS;
2229 bc_vec_init(&stack, sizeof(long), NULL);
2230 bc_num_init(&intp, n->len);
2231 bc_num_init(&fracp, n->rdx);
2232 bc_num_init(&digit, width);
2233 bc_num_init(&frac_len, BC_NUM_INT(n));
2234 bc_num_copy(&intp, n);
2235 bc_num_one(&frac_len);
2237 bc_num_truncate(&intp, intp.rdx);
2238 s = bc_num_sub(n, &intp, &fracp, 0);
2241 while (intp.len != 0) {
2242 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2244 s = bc_num_ulong(&digit, &dig);
2246 bc_vec_push(&stack, &dig);
2249 for (i = 0; i < stack.len; ++i) {
2250 ptr = bc_vec_item_rev(&stack, i);
2251 print(*ptr, width, false, nchars, len);
2254 if (!n->rdx) goto err;
2256 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2257 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2259 s = bc_num_ulong(&fracp, &dig);
2261 bc_num_ulong2num(&intp, dig);
2262 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2264 print(dig, width, radix, nchars, len);
2265 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2270 bc_num_free(&frac_len);
2271 bc_num_free(&digit);
2272 bc_num_free(&fracp);
2274 bc_vec_free(&stack);
2278 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2279 size_t *nchars, size_t line_len)
2286 if (neg) bb_putchar('-');
2291 if (base_t <= BC_NUM_MAX_IBASE) {
2293 print = bc_num_printHex;
2296 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2297 print = bc_num_printDigits;
2300 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2307 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2309 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2313 static void bc_num_init(BcNum *n, size_t req)
2315 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2316 memset(n, 0, sizeof(BcNum));
2317 n->num = xmalloc(req);
2321 static void bc_num_expand(BcNum *n, size_t req)
2323 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2325 n->num = xrealloc(n->num, req);
2330 static void bc_num_free(void *num)
2332 free(((BcNum *) num)->num);
2335 static void bc_num_copy(BcNum *d, BcNum *s)
2338 bc_num_expand(d, s->cap);
2342 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2346 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2349 if (!bc_num_strValid(val, base_t))
2350 return bc_error("bad number string");
2353 bc_num_parseDecimal(n, val);
2355 bc_num_parseBase(n, val, base);
2357 return BC_STATUS_SUCCESS;
2360 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2361 size_t *nchars, size_t line_len)
2363 BcStatus s = BC_STATUS_SUCCESS;
2365 bc_num_printNewline(nchars, line_len);
2371 else if (base_t == 10)
2372 bc_num_printDecimal(n, nchars, line_len);
2374 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2384 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2389 if (n->neg) return bc_error("negative number");
2391 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2393 unsigned long prev = *result, powprev = pow;
2395 *result += ((unsigned long) n->num[i]) * pow;
2398 if (*result < prev || pow < powprev)
2399 return bc_error("overflow");
2402 return BC_STATUS_SUCCESS;
2405 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2413 if (val == 0) return;
2415 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2416 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2419 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2421 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2423 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2426 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2428 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2430 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2433 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2435 size_t req = BC_NUM_MREQ(a, b, scale);
2436 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2439 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2441 size_t req = BC_NUM_MREQ(a, b, scale);
2442 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2445 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2447 size_t req = BC_NUM_MREQ(a, b, scale);
2448 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2451 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2453 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2456 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2459 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2460 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2461 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2463 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2464 bc_num_expand(b, req);
2467 bc_num_setToZero(b, scale);
2468 return BC_STATUS_SUCCESS;
2471 return bc_error("negative number");
2472 else if (BC_NUM_ONE(a)) {
2474 bc_num_extend(b, scale);
2475 return BC_STATUS_SUCCESS;
2478 scale = BC_MAX(scale, a->rdx) + 1;
2479 len = a->len + scale;
2481 bc_num_init(&num1, len);
2482 bc_num_init(&num2, len);
2483 bc_num_init(&half, BC_NUM_DEF_SIZE);
2489 bc_num_init(&f, len);
2490 bc_num_init(&fprime, len);
2496 pow = BC_NUM_INT(a);
2505 pow -= 2 - (pow & 1);
2507 bc_num_extend(x0, pow);
2509 // Make sure to move the radix back.
2513 x0->rdx = digs = digs1 = 0;
2515 len = BC_NUM_INT(x0) + resrdx - 1;
2517 while (cmp != 0 || digs < len) {
2519 s = bc_num_div(a, x0, &f, resrdx);
2521 s = bc_num_add(x0, &f, &fprime, resrdx);
2523 s = bc_num_mul(&fprime, &half, x1, resrdx);
2526 cmp = bc_num_cmp(x1, x0);
2527 digs = x1->len - (unsigned long long) llabs(cmp);
2529 if (cmp == cmp2 && digs == digs1)
2534 resrdx += times > 4;
2547 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2550 bc_num_free(&fprime);
2558 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2564 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2567 memcpy(&num2, c, sizeof(BcNum));
2569 bc_num_init(c, len);
2574 bc_num_expand(c, len);
2577 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2579 if (init) bc_num_free(&num2);
2585 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2588 BcNum base, exp, two, temp;
2591 return bc_error("divide by zero");
2592 if (a->rdx || b->rdx || c->rdx)
2593 return bc_error("non integer number");
2595 return bc_error("negative number");
2597 bc_num_expand(d, c->len);
2598 bc_num_init(&base, c->len);
2599 bc_num_init(&exp, b->len);
2600 bc_num_init(&two, BC_NUM_DEF_SIZE);
2601 bc_num_init(&temp, b->len);
2607 s = bc_num_rem(a, c, &base, 0);
2609 bc_num_copy(&exp, b);
2611 while (exp.len != 0) {
2613 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2616 if (BC_NUM_ONE(&temp)) {
2617 s = bc_num_mul(d, &base, &temp, 0);
2619 s = bc_num_rem(&temp, c, d, 0);
2623 s = bc_num_mul(&base, &base, &temp, 0);
2625 s = bc_num_rem(&temp, c, &base, 0);
2638 static int bc_id_cmp(const void *e1, const void *e2)
2640 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2643 static void bc_id_free(void *id)
2645 free(((BcId *) id)->name);
2648 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2653 for (i = 0; i < f->autos.len; ++i) {
2654 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2655 return bc_error("function parameter or auto var has the same name as another");
2661 bc_vec_push(&f->autos, &a);
2663 return BC_STATUS_SUCCESS;
2666 static void bc_func_init(BcFunc *f)
2668 bc_char_vec_init(&f->code);
2669 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2670 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2674 static void bc_func_free(void *func)
2676 BcFunc *f = (BcFunc *) func;
2677 bc_vec_free(&f->code);
2678 bc_vec_free(&f->autos);
2679 bc_vec_free(&f->labels);
2682 static void bc_array_init(BcVec *a, bool nums)
2685 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2687 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2688 bc_array_expand(a, 1);
2691 static void bc_array_copy(BcVec *d, const BcVec *s)
2696 bc_vec_expand(d, s->cap);
2699 for (i = 0; i < s->len; ++i) {
2700 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2701 bc_num_init(dnum, snum->len);
2702 bc_num_copy(dnum, snum);
2706 static void bc_array_expand(BcVec *a, size_t len)
2710 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2711 while (len > a->len) {
2712 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2713 bc_vec_push(a, &data.n);
2717 while (len > a->len) {
2718 bc_array_init(&data.v, true);
2719 bc_vec_push(a, &data.v);
2724 static void bc_string_free(void *string)
2726 free(*((char **) string));
2730 static void bc_result_copy(BcResult *d, BcResult *src)
2736 case BC_RESULT_TEMP:
2737 case BC_RESULT_IBASE:
2738 case BC_RESULT_SCALE:
2739 case BC_RESULT_OBASE:
2741 bc_num_init(&d->d.n, src->d.n.len);
2742 bc_num_copy(&d->d.n, &src->d.n);
2747 case BC_RESULT_ARRAY:
2748 case BC_RESULT_ARRAY_ELEM:
2750 d->d.id.name = xstrdup(src->d.id.name);
2754 case BC_RESULT_CONSTANT:
2755 case BC_RESULT_LAST:
2759 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2766 static void bc_result_free(void *result)
2768 BcResult *r = (BcResult *) result;
2772 case BC_RESULT_TEMP:
2773 case BC_RESULT_IBASE:
2774 case BC_RESULT_SCALE:
2775 case BC_RESULT_OBASE:
2777 bc_num_free(&r->d.n);
2782 case BC_RESULT_ARRAY:
2783 case BC_RESULT_ARRAY_ELEM:
2797 static void bc_lex_lineComment(BcLex *l)
2799 l->t.t = BC_LEX_WHITESPACE;
2800 while (l->i < l->len && l->buf[l->i++] != '\n');
2804 static void bc_lex_whitespace(BcLex *l)
2807 l->t.t = BC_LEX_WHITESPACE;
2808 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2811 static BcStatus bc_lex_number(BcLex *l, char start)
2813 const char *buf = l->buf + l->i;
2814 size_t len, hits = 0, bslashes = 0, i = 0, j;
2816 bool last_pt, pt = start == '.';
2819 l->t.t = BC_LEX_NUMBER;
2821 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2822 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2836 len = i + !last_pt - bslashes * 2;
2837 if (len > BC_MAX_NUM)
2838 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2840 bc_vec_pop_all(&l->t.v);
2841 bc_vec_expand(&l->t.v, len + 1);
2842 bc_vec_push(&l->t.v, &start);
2844 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2848 // If we have hit a backslash, skip it. We don't have
2849 // to check for a newline because it's guaranteed.
2850 if (hits < bslashes && c == '\\') {
2856 bc_vec_push(&l->t.v, &c);
2859 bc_vec_pushZeroByte(&l->t.v);
2862 return BC_STATUS_SUCCESS;
2865 static BcStatus bc_lex_name(BcLex *l)
2868 const char *buf = l->buf + l->i - 1;
2871 l->t.t = BC_LEX_NAME;
2873 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2875 if (i > BC_MAX_STRING)
2876 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2877 bc_vec_string(&l->t.v, i, buf);
2879 // Increment the index. We minus 1 because it has already been incremented.
2882 return BC_STATUS_SUCCESS;
2885 static void bc_lex_init(BcLex *l, BcLexNext next)
2888 bc_char_vec_init(&l->t.v);
2891 static void bc_lex_free(BcLex *l)
2893 bc_vec_free(&l->t.v);
2896 static void bc_lex_file(BcLex *l)
2898 G.err_line = l->line = 1;
2902 static BcStatus bc_lex_next(BcLex *l)
2907 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2909 l->line += l->newline;
2910 G.err_line = l->line;
2911 l->t.t = BC_LEX_EOF;
2913 l->newline = (l->i == l->len);
2914 if (l->newline) return BC_STATUS_SUCCESS;
2916 // Loop until failure or we don't have whitespace. This
2917 // is so the parser doesn't get inundated with whitespace.
2920 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2925 static BcStatus bc_lex_text(BcLex *l, const char *text)
2929 l->len = strlen(text);
2930 l->t.t = l->t.last = BC_LEX_INVALID;
2931 return bc_lex_next(l);
2935 static BcStatus bc_lex_identifier(BcLex *l)
2939 const char *buf = l->buf + l->i - 1;
2941 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2942 const char *keyword8 = bc_lex_kws[i].name8;
2944 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2946 if (j == 8) goto match;
2948 if (keyword8[j] != '\0')
2951 // buf starts with keyword bc_lex_kws[i]
2952 l->t.t = BC_LEX_KEY_1st_keyword + i;
2953 if (!((1 << i) & POSIX_KWORD_MASK)) {
2954 s = bc_posix_error_fmt("%sthe following keyword: '%.8s'", "POSIX does not allow ", bc_lex_kws[i].name8);
2958 // We minus 1 because the index has already been incremented.
2960 return BC_STATUS_SUCCESS;
2967 s = bc_posix_error_fmt("POSIX only allows one character names; the following is bad: '%s'", buf);
2972 static BcStatus bc_lex_string(BcLex *l)
2974 size_t len, nls = 0, i = l->i;
2977 l->t.t = BC_LEX_STR;
2979 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2983 return bc_error("string end could not be found");
2987 if (len > BC_MAX_STRING)
2988 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2989 bc_vec_string(&l->t.v, len, l->buf + l->i);
2993 G.err_line = l->line;
2995 return BC_STATUS_SUCCESS;
2998 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3000 if (l->buf[l->i] == '=') {
3008 static BcStatus bc_lex_comment(BcLex *l)
3011 const char *buf = l->buf;
3013 l->t.t = BC_LEX_WHITESPACE;
3026 return bc_error("comment end could not be found");
3034 G.err_line = l->line;
3036 return BC_STATUS_SUCCESS;
3039 static BcStatus bc_lex_token(BcLex *l)
3041 BcStatus s = BC_STATUS_SUCCESS;
3042 char c = l->buf[l->i++], c2;
3044 // This is the workhorse of the lexer.
3051 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3061 bc_lex_whitespace(l);
3067 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3069 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3070 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
3079 s = bc_lex_string(l);
3085 s = bc_POSIX_does_not_allow("'#' script comments");
3088 bc_lex_lineComment(l);
3095 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3104 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
3108 l->t.t = BC_LEX_OP_BOOL_AND;
3111 l->t.t = BC_LEX_INVALID;
3112 s = bc_error_bad_character('&');
3121 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3127 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3136 l->t.t = BC_LEX_OP_INC;
3139 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3145 l->t.t = BC_LEX_COMMA;
3154 l->t.t = BC_LEX_OP_DEC;
3157 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3163 if (isdigit(l->buf[l->i]))
3164 s = bc_lex_number(l, c);
3166 l->t.t = BC_LEX_KEY_LAST;
3167 s = bc_POSIX_does_not_allow("a period ('.') as a shortcut for the last result");
3176 s = bc_lex_comment(l);
3178 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3199 s = bc_lex_number(l, c);
3205 l->t.t = BC_LEX_SCOLON;
3211 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3217 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3223 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3230 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3236 if (l->buf[l->i] == '\n') {
3237 l->t.t = BC_LEX_WHITESPACE;
3241 s = bc_error_bad_character(c);
3247 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3278 s = bc_lex_identifier(l);
3285 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3294 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
3298 l->t.t = BC_LEX_OP_BOOL_OR;
3301 l->t.t = BC_LEX_INVALID;
3302 s = bc_error_bad_character(c);
3310 l->t.t = BC_LEX_INVALID;
3311 s = bc_error_bad_character(c);
3321 static BcStatus dc_lex_register(BcLex *l)
3323 BcStatus s = BC_STATUS_SUCCESS;
3325 if (isspace(l->buf[l->i - 1])) {
3326 bc_lex_whitespace(l);
3329 s = bc_error("extended register");
3334 bc_vec_pop_all(&l->t.v);
3335 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3336 bc_vec_pushZeroByte(&l->t.v);
3337 l->t.t = BC_LEX_NAME;
3343 static BcStatus dc_lex_string(BcLex *l)
3345 size_t depth = 1, nls = 0, i = l->i;
3348 l->t.t = BC_LEX_STR;
3349 bc_vec_pop_all(&l->t.v);
3351 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3353 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3354 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3357 if (depth) bc_vec_push(&l->t.v, &c);
3362 return bc_error("string end could not be found");
3365 bc_vec_pushZeroByte(&l->t.v);
3366 if (i - l->i > BC_MAX_STRING)
3367 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3371 G.err_line = l->line;
3373 return BC_STATUS_SUCCESS;
3376 static BcStatus dc_lex_token(BcLex *l)
3378 BcStatus s = BC_STATUS_SUCCESS;
3379 char c = l->buf[l->i++], c2;
3382 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3383 if (l->t.last == dc_lex_regs[i])
3384 return dc_lex_register(l);
3387 if (c >= '%' && c <= '~' &&
3388 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3393 // This is the workhorse of the lexer.
3398 l->t.t = BC_LEX_EOF;
3409 l->newline = (c == '\n');
3410 bc_lex_whitespace(l);
3419 l->t.t = BC_LEX_OP_REL_NE;
3421 l->t.t = BC_LEX_OP_REL_LE;
3423 l->t.t = BC_LEX_OP_REL_GE;
3425 return bc_error_bad_character(c);
3433 bc_lex_lineComment(l);
3439 if (isdigit(l->buf[l->i]))
3440 s = bc_lex_number(l, c);
3442 s = bc_error_bad_character(c);
3463 s = bc_lex_number(l, c);
3469 s = dc_lex_string(l);
3475 l->t.t = BC_LEX_INVALID;
3476 s = bc_error_bad_character(c);
3485 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3487 bc_program_addFunc(name, idx);
3488 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3491 static void bc_parse_pushName(BcParse *p, char *name)
3493 size_t i = 0, len = strlen(name);
3495 for (; i < len; ++i) bc_parse_push(p, name[i]);
3496 bc_parse_push(p, BC_PARSE_STREND);
3501 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3503 unsigned char amt, i, nums[sizeof(size_t)];
3505 for (amt = 0; idx; ++amt) {
3506 nums[amt] = (char) idx;
3507 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3510 bc_parse_push(p, amt);
3511 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3514 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3516 char *num = xstrdup(p->l.t.v.v);
3517 size_t idx = G.prog.consts.len;
3519 bc_vec_push(&G.prog.consts, &num);
3521 bc_parse_push(p, BC_INST_NUM);
3522 bc_parse_pushIndex(p, idx);
3525 (*prev) = BC_INST_NUM;
3528 static BcStatus bc_parse_text(BcParse *p, const char *text)
3532 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3534 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3535 p->l.t.t = BC_LEX_INVALID;
3538 if (!BC_PARSE_CAN_EXEC(p))
3539 return bc_error("file is not executable");
3542 return bc_lex_text(&p->l, text);
3545 // Called when bc/dc_parse_parse() detects a failure,
3546 // resets parsing structures.
3547 static void bc_parse_reset(BcParse *p)
3549 if (p->fidx != BC_PROG_MAIN) {
3550 p->func->nparams = 0;
3551 bc_vec_pop_all(&p->func->code);
3552 bc_vec_pop_all(&p->func->autos);
3553 bc_vec_pop_all(&p->func->labels);
3555 bc_parse_updateFunc(p, BC_PROG_MAIN);
3559 p->l.t.t = BC_LEX_EOF;
3560 p->auto_part = (p->nbraces = 0);
3562 bc_vec_npop(&p->flags, p->flags.len - 1);
3563 bc_vec_pop_all(&p->exits);
3564 bc_vec_pop_all(&p->conds);
3565 bc_vec_pop_all(&p->ops);
3570 static void bc_parse_free(BcParse *p)
3572 bc_vec_free(&p->flags);
3573 bc_vec_free(&p->exits);
3574 bc_vec_free(&p->conds);
3575 bc_vec_free(&p->ops);
3579 static void bc_parse_create(BcParse *p, size_t func,
3580 BcParseParse parse, BcLexNext next)
3582 memset(p, 0, sizeof(BcParse));
3584 bc_lex_init(&p->l, next);
3585 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3586 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3587 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3588 bc_vec_pushZeroByte(&p->flags);
3589 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3592 // p->auto_part = p->nbraces = 0; - already is
3593 bc_parse_updateFunc(p, func);
3597 static BcStatus bc_parse_else(BcParse *p);
3598 static BcStatus bc_parse_stmt(BcParse *p);
3600 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3601 size_t *nexprs, bool next)
3603 BcStatus s = BC_STATUS_SUCCESS;
3605 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3606 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3608 while (p->ops.len > start) {
3610 t = BC_PARSE_TOP_OP(p);
3611 if (t == BC_LEX_LPAREN) break;
3613 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3614 if (l >= r && (l != r || !left)) break;
3616 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3617 bc_vec_pop(&p->ops);
3618 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3621 bc_vec_push(&p->ops, &type);
3622 if (next) s = bc_lex_next(&p->l);
3627 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3631 if (p->ops.len <= ops_bgn)
3632 return bc_error_bad_expression();
3633 top = BC_PARSE_TOP_OP(p);
3635 while (top != BC_LEX_LPAREN) {
3637 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3639 bc_vec_pop(&p->ops);
3640 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3642 if (p->ops.len <= ops_bgn)
3643 return bc_error_bad_expression();
3644 top = BC_PARSE_TOP_OP(p);
3647 bc_vec_pop(&p->ops);
3649 return bc_lex_next(&p->l);
3652 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3658 s = bc_lex_next(&p->l);
3661 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3663 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3664 s = bc_parse_expr(p, flags, bc_parse_next_param);
3667 comma = p->l.t.t == BC_LEX_COMMA;
3669 s = bc_lex_next(&p->l);
3674 if (comma) return bc_error_bad_token();
3675 bc_parse_push(p, BC_INST_CALL);
3676 bc_parse_pushIndex(p, nparams);
3678 return BC_STATUS_SUCCESS;
3681 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3684 BcId entry, *entry_ptr;
3689 s = bc_parse_params(p, flags);
3692 if (p->l.t.t != BC_LEX_RPAREN) {
3693 s = bc_error_bad_token();
3697 idx = bc_map_index(&G.prog.fn_map, &entry);
3699 if (idx == BC_VEC_INVALID_IDX) {
3700 name = xstrdup(entry.name);
3701 bc_parse_addFunc(p, name, &idx);
3702 idx = bc_map_index(&G.prog.fn_map, &entry);
3708 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3709 bc_parse_pushIndex(p, entry_ptr->idx);
3711 return bc_lex_next(&p->l);
3718 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3723 name = xstrdup(p->l.t.v.v);
3724 s = bc_lex_next(&p->l);
3727 if (p->l.t.t == BC_LEX_LBRACKET) {
3729 s = bc_lex_next(&p->l);
3732 if (p->l.t.t == BC_LEX_RBRACKET) {
3734 if (!(flags & BC_PARSE_ARRAY)) {
3735 s = bc_error_bad_expression();
3739 *type = BC_INST_ARRAY;
3743 *type = BC_INST_ARRAY_ELEM;
3745 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3746 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3750 s = bc_lex_next(&p->l);
3752 bc_parse_push(p, *type);
3753 bc_parse_pushName(p, name);
3755 else if (p->l.t.t == BC_LEX_LPAREN) {
3757 if (flags & BC_PARSE_NOCALL) {
3758 s = bc_error_bad_token();
3762 *type = BC_INST_CALL;
3763 s = bc_parse_call(p, name, flags);
3766 *type = BC_INST_VAR;
3767 bc_parse_push(p, BC_INST_VAR);
3768 bc_parse_pushName(p, name);
3778 static BcStatus bc_parse_read(BcParse *p)
3782 s = bc_lex_next(&p->l);
3784 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3786 s = bc_lex_next(&p->l);
3788 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3790 bc_parse_push(p, BC_INST_READ);
3792 return bc_lex_next(&p->l);
3795 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3800 s = bc_lex_next(&p->l);
3802 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
3804 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3806 s = bc_lex_next(&p->l);
3809 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3812 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3814 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3815 bc_parse_push(p, *prev);
3817 return bc_lex_next(&p->l);
3820 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3824 s = bc_lex_next(&p->l);
3827 if (p->l.t.t != BC_LEX_LPAREN) {
3828 *type = BC_INST_SCALE;
3829 bc_parse_push(p, BC_INST_SCALE);
3830 return BC_STATUS_SUCCESS;
3833 *type = BC_INST_SCALE_FUNC;
3834 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3836 s = bc_lex_next(&p->l);
3839 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3841 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
3842 bc_parse_push(p, BC_INST_SCALE_FUNC);
3844 return bc_lex_next(&p->l);
3847 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3848 size_t *nexprs, uint8_t flags)
3853 BcInst etype = *prev;
3855 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3856 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3857 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3859 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3860 bc_parse_push(p, inst);
3861 s = bc_lex_next(&p->l);
3865 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3868 s = bc_lex_next(&p->l);
3872 // Because we parse the next part of the expression
3873 // right here, we need to increment this.
3874 *nexprs = *nexprs + 1;
3880 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3884 case BC_LEX_KEY_IBASE:
3885 case BC_LEX_KEY_LAST:
3886 case BC_LEX_KEY_OBASE:
3888 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3889 s = bc_lex_next(&p->l);
3893 case BC_LEX_KEY_SCALE:
3895 s = bc_lex_next(&p->l);
3897 if (p->l.t.t == BC_LEX_LPAREN)
3898 s = bc_error_bad_token();
3900 bc_parse_push(p, BC_INST_SCALE);
3906 s = bc_error_bad_token();
3911 if (!s) bc_parse_push(p, inst);
3917 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3918 bool rparen, size_t *nexprs)
3922 BcInst etype = *prev;
3924 s = bc_lex_next(&p->l);
3927 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3928 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3931 *prev = BC_PARSE_TOKEN_INST(type);
3933 // We can just push onto the op stack because this is the largest
3934 // precedence operator that gets pushed. Inc/dec does not.
3935 if (type != BC_LEX_OP_MINUS)
3936 bc_vec_push(&p->ops, &type);
3938 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3943 static BcStatus bc_parse_string(BcParse *p, char inst)
3945 char *str = xstrdup(p->l.t.v.v);
3947 bc_parse_push(p, BC_INST_STR);
3948 bc_parse_pushIndex(p, G.prog.strs.len);
3949 bc_vec_push(&G.prog.strs, &str);
3950 bc_parse_push(p, inst);
3952 return bc_lex_next(&p->l);
3955 static BcStatus bc_parse_print(BcParse *p)
3961 s = bc_lex_next(&p->l);
3966 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3967 return bc_error("bad print statement");
3969 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3971 if (type == BC_LEX_STR)
3972 s = bc_parse_string(p, BC_INST_PRINT_POP);
3974 s = bc_parse_expr(p, 0, bc_parse_next_print);
3976 bc_parse_push(p, BC_INST_PRINT_POP);
3981 comma = p->l.t.t == BC_LEX_COMMA;
3982 if (comma) s = bc_lex_next(&p->l);
3987 if (comma) return bc_error_bad_token();
3989 return bc_lex_next(&p->l);
3992 static BcStatus bc_parse_return(BcParse *p)
3998 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
4000 s = bc_lex_next(&p->l);
4004 paren = t == BC_LEX_LPAREN;
4006 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4007 bc_parse_push(p, BC_INST_RET0);
4010 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4011 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4014 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4015 bc_parse_push(p, BC_INST_RET0);
4016 s = bc_lex_next(&p->l);
4020 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4021 s = bc_posix_error("POSIX requires parentheses around return expressions");
4025 bc_parse_push(p, BC_INST_RET);
4031 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4033 BcStatus s = BC_STATUS_SUCCESS;
4035 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4036 return bc_error_bad_token();
4040 if (p->l.t.t == BC_LEX_RBRACE) {
4041 if (!p->nbraces) return bc_error_bad_token();
4043 s = bc_lex_next(&p->l);
4047 return bc_error_bad_token();
4050 if (BC_PARSE_IF(p)) {
4054 while (p->l.t.t == BC_LEX_NLINE) {
4055 s = bc_lex_next(&p->l);
4059 bc_vec_pop(&p->flags);
4061 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4062 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4064 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4066 else if (BC_PARSE_ELSE(p)) {
4071 bc_vec_pop(&p->flags);
4073 ip = bc_vec_top(&p->exits);
4074 label = bc_vec_item(&p->func->labels, ip->idx);
4075 *label = p->func->code.len;
4077 bc_vec_pop(&p->exits);
4079 else if (BC_PARSE_FUNC_INNER(p)) {
4080 bc_parse_push(p, BC_INST_RET0);
4081 bc_parse_updateFunc(p, BC_PROG_MAIN);
4082 bc_vec_pop(&p->flags);
4086 BcInstPtr *ip = bc_vec_top(&p->exits);
4087 size_t *label = bc_vec_top(&p->conds);
4089 bc_parse_push(p, BC_INST_JUMP);
4090 bc_parse_pushIndex(p, *label);
4092 label = bc_vec_item(&p->func->labels, ip->idx);
4093 *label = p->func->code.len;
4095 bc_vec_pop(&p->flags);
4096 bc_vec_pop(&p->exits);
4097 bc_vec_pop(&p->conds);
4103 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4105 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4106 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4107 flags |= BC_PARSE_FLAG_BODY;
4108 bc_vec_push(&p->flags, &flags);
4111 static void bc_parse_noElse(BcParse *p)
4115 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4117 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4119 ip = bc_vec_top(&p->exits);
4120 label = bc_vec_item(&p->func->labels, ip->idx);
4121 *label = p->func->code.len;
4123 bc_vec_pop(&p->exits);
4126 static BcStatus bc_parse_if(BcParse *p)
4131 s = bc_lex_next(&p->l);
4133 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4135 s = bc_lex_next(&p->l);
4137 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4139 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4141 s = bc_lex_next(&p->l);
4143 bc_parse_push(p, BC_INST_JUMP_ZERO);
4145 ip.idx = p->func->labels.len;
4146 ip.func = ip.len = 0;
4148 bc_parse_pushIndex(p, ip.idx);
4149 bc_vec_push(&p->exits, &ip);
4150 bc_vec_push(&p->func->labels, &ip.idx);
4151 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4153 return BC_STATUS_SUCCESS;
4156 static BcStatus bc_parse_else(BcParse *p)
4160 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
4162 ip.idx = p->func->labels.len;
4163 ip.func = ip.len = 0;
4165 bc_parse_push(p, BC_INST_JUMP);
4166 bc_parse_pushIndex(p, ip.idx);
4170 bc_vec_push(&p->exits, &ip);
4171 bc_vec_push(&p->func->labels, &ip.idx);
4172 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4174 return bc_lex_next(&p->l);
4177 static BcStatus bc_parse_while(BcParse *p)
4182 s = bc_lex_next(&p->l);
4184 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4185 s = bc_lex_next(&p->l);
4188 ip.idx = p->func->labels.len;
4190 bc_vec_push(&p->func->labels, &p->func->code.len);
4191 bc_vec_push(&p->conds, &ip.idx);
4193 ip.idx = p->func->labels.len;
4197 bc_vec_push(&p->exits, &ip);
4198 bc_vec_push(&p->func->labels, &ip.idx);
4200 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4202 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4203 s = bc_lex_next(&p->l);
4206 bc_parse_push(p, BC_INST_JUMP_ZERO);
4207 bc_parse_pushIndex(p, ip.idx);
4208 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4210 return BC_STATUS_SUCCESS;
4213 static BcStatus bc_parse_for(BcParse *p)
4217 size_t cond_idx, exit_idx, body_idx, update_idx;
4219 s = bc_lex_next(&p->l);
4221 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
4222 s = bc_lex_next(&p->l);
4225 if (p->l.t.t != BC_LEX_SCOLON)
4226 s = bc_parse_expr(p, 0, bc_parse_next_for);
4228 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
4231 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4232 s = bc_lex_next(&p->l);
4235 cond_idx = p->func->labels.len;
4236 update_idx = cond_idx + 1;
4237 body_idx = update_idx + 1;
4238 exit_idx = body_idx + 1;
4240 bc_vec_push(&p->func->labels, &p->func->code.len);
4242 if (p->l.t.t != BC_LEX_SCOLON)
4243 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4245 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
4248 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
4250 s = bc_lex_next(&p->l);
4253 bc_parse_push(p, BC_INST_JUMP_ZERO);
4254 bc_parse_pushIndex(p, exit_idx);
4255 bc_parse_push(p, BC_INST_JUMP);
4256 bc_parse_pushIndex(p, body_idx);
4258 ip.idx = p->func->labels.len;
4260 bc_vec_push(&p->conds, &update_idx);
4261 bc_vec_push(&p->func->labels, &p->func->code.len);
4263 if (p->l.t.t != BC_LEX_RPAREN)
4264 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4266 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
4270 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
4271 bc_parse_push(p, BC_INST_JUMP);
4272 bc_parse_pushIndex(p, cond_idx);
4273 bc_vec_push(&p->func->labels, &p->func->code.len);
4279 bc_vec_push(&p->exits, &ip);
4280 bc_vec_push(&p->func->labels, &ip.idx);
4282 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4284 return BC_STATUS_SUCCESS;
4287 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4293 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
4295 if (type == BC_LEX_KEY_BREAK) {
4297 if (p->exits.len == 0) return bc_error_bad_token();
4299 i = p->exits.len - 1;
4300 ip = bc_vec_item(&p->exits, i);
4302 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4303 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
4308 i = *((size_t *) bc_vec_top(&p->conds));
4310 bc_parse_push(p, BC_INST_JUMP);
4311 bc_parse_pushIndex(p, i);
4313 s = bc_lex_next(&p->l);
4316 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4317 return bc_error_bad_token();
4319 return bc_lex_next(&p->l);
4322 static BcStatus bc_parse_func(BcParse *p)
4325 bool var, comma = false;
4329 s = bc_lex_next(&p->l);
4331 if (p->l.t.t != BC_LEX_NAME)
4332 return bc_error("bad function definition");
4334 name = xstrdup(p->l.t.v.v);
4335 bc_parse_addFunc(p, name, &p->fidx);
4337 s = bc_lex_next(&p->l);
4339 if (p->l.t.t != BC_LEX_LPAREN)
4340 return bc_error("bad function definition");
4341 s = bc_lex_next(&p->l);
4344 while (p->l.t.t != BC_LEX_RPAREN) {
4346 if (p->l.t.t != BC_LEX_NAME)
4347 return bc_error("bad function definition");
4351 name = xstrdup(p->l.t.v.v);
4352 s = bc_lex_next(&p->l);
4355 var = p->l.t.t != BC_LEX_LBRACKET;
4359 s = bc_lex_next(&p->l);
4362 if (p->l.t.t != BC_LEX_RBRACKET) {
4363 s = bc_error("bad function definition");
4367 s = bc_lex_next(&p->l);
4371 comma = p->l.t.t == BC_LEX_COMMA;
4373 s = bc_lex_next(&p->l);
4377 s = bc_func_insert(p->func, name, var);
4381 if (comma) return bc_error("bad function definition");
4383 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4384 bc_parse_startBody(p, flags);
4386 s = bc_lex_next(&p->l);
4389 if (p->l.t.t != BC_LEX_LBRACE)
4390 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4399 static BcStatus bc_parse_auto(BcParse *p)
4402 bool comma, var, one;
4405 if (!p->auto_part) return bc_error_bad_token();
4406 s = bc_lex_next(&p->l);
4409 p->auto_part = comma = false;
4410 one = p->l.t.t == BC_LEX_NAME;
4412 while (p->l.t.t == BC_LEX_NAME) {
4414 name = xstrdup(p->l.t.v.v);
4415 s = bc_lex_next(&p->l);
4418 var = p->l.t.t != BC_LEX_LBRACKET;
4421 s = bc_lex_next(&p->l);
4424 if (p->l.t.t != BC_LEX_RBRACKET) {
4425 s = bc_error("bad function definition");
4429 s = bc_lex_next(&p->l);
4433 comma = p->l.t.t == BC_LEX_COMMA;
4435 s = bc_lex_next(&p->l);
4439 s = bc_func_insert(p->func, name, var);
4443 if (comma) return bc_error("bad function definition");
4444 if (!one) return bc_error("no auto variable found");
4446 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4447 return bc_error_bad_token();
4449 return bc_lex_next(&p->l);
4456 static BcStatus bc_parse_body(BcParse *p, bool brace)
4458 BcStatus s = BC_STATUS_SUCCESS;
4459 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4461 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4463 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4465 if (!brace) return bc_error_bad_token();
4466 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4468 if (!p->auto_part) {
4469 s = bc_parse_auto(p);
4473 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4476 s = bc_parse_stmt(p);
4477 if (!s && !brace) s = bc_parse_endBody(p, false);
4483 static BcStatus bc_parse_stmt(BcParse *p)
4485 BcStatus s = BC_STATUS_SUCCESS;
4491 return bc_lex_next(&p->l);
4494 case BC_LEX_KEY_ELSE:
4496 p->auto_part = false;
4502 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
4505 s = bc_lex_next(&p->l);
4508 return bc_parse_body(p, true);
4511 case BC_LEX_KEY_AUTO:
4513 return bc_parse_auto(p);
4518 p->auto_part = false;
4520 if (BC_PARSE_IF_END(p)) {
4522 return BC_STATUS_SUCCESS;
4524 else if (BC_PARSE_BODY(p))
4525 return bc_parse_body(p, false);
4535 case BC_LEX_OP_MINUS:
4536 case BC_LEX_OP_BOOL_NOT:
4540 case BC_LEX_KEY_IBASE:
4541 case BC_LEX_KEY_LAST:
4542 case BC_LEX_KEY_LENGTH:
4543 case BC_LEX_KEY_OBASE:
4544 case BC_LEX_KEY_READ:
4545 case BC_LEX_KEY_SCALE:
4546 case BC_LEX_KEY_SQRT:
4548 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4552 case BC_LEX_KEY_ELSE:
4554 s = bc_parse_else(p);
4560 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4566 s = bc_parse_endBody(p, true);
4572 s = bc_parse_string(p, BC_INST_PRINT_STR);
4576 case BC_LEX_KEY_BREAK:
4577 case BC_LEX_KEY_CONTINUE:
4579 s = bc_parse_loopExit(p, p->l.t.t);
4583 case BC_LEX_KEY_FOR:
4585 s = bc_parse_for(p);
4589 case BC_LEX_KEY_HALT:
4591 bc_parse_push(p, BC_INST_HALT);
4592 s = bc_lex_next(&p->l);
4602 case BC_LEX_KEY_LIMITS:
4604 // "limits" is a compile-time command,
4605 // the output is produced at _parse time_.
4606 s = bc_lex_next(&p->l);
4608 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4609 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4610 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4611 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4612 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4613 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4614 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4615 printf("Number of vars = %lu\n", BC_MAX_VARS);
4619 case BC_LEX_KEY_PRINT:
4621 s = bc_parse_print(p);
4625 case BC_LEX_KEY_QUIT:
4627 // "quit" is a compile-time command. For example,
4628 // "if (0 == 1) quit" terminates when parsing the statement,
4629 // not when it is executed
4633 case BC_LEX_KEY_RETURN:
4635 s = bc_parse_return(p);
4639 case BC_LEX_KEY_WHILE:
4641 s = bc_parse_while(p);
4647 s = bc_error_bad_token();
4655 static BcStatus bc_parse_parse(BcParse *p)
4659 if (p->l.t.t == BC_LEX_EOF)
4660 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4661 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4662 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
4663 s = bc_parse_func(p);
4666 s = bc_parse_stmt(p);
4668 if (s || G_interrupt) {
4670 s = BC_STATUS_FAILURE;
4676 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4678 BcStatus s = BC_STATUS_SUCCESS;
4679 BcInst prev = BC_INST_PRINT;
4680 BcLexType top, t = p->l.t.t;
4681 size_t nexprs = 0, ops_bgn = p->ops.len;
4682 uint32_t i, nparens, nrelops;
4683 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4685 paren_first = p->l.t.t == BC_LEX_LPAREN;
4686 nparens = nrelops = 0;
4687 paren_expr = rprn = done = get_token = assign = false;
4690 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4696 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4697 rprn = get_token = bin_last = false;
4701 case BC_LEX_OP_MINUS:
4703 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4704 rprn = get_token = false;
4705 bin_last = prev == BC_INST_MINUS;
4709 case BC_LEX_OP_ASSIGN_POWER:
4710 case BC_LEX_OP_ASSIGN_MULTIPLY:
4711 case BC_LEX_OP_ASSIGN_DIVIDE:
4712 case BC_LEX_OP_ASSIGN_MODULUS:
4713 case BC_LEX_OP_ASSIGN_PLUS:
4714 case BC_LEX_OP_ASSIGN_MINUS:
4715 case BC_LEX_OP_ASSIGN:
4717 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4718 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4719 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4721 s = bc_error("bad assignment:"
4722 " left side must be scale,"
4723 " ibase, obase, last, var,"
4730 case BC_LEX_OP_POWER:
4731 case BC_LEX_OP_MULTIPLY:
4732 case BC_LEX_OP_DIVIDE:
4733 case BC_LEX_OP_MODULUS:
4734 case BC_LEX_OP_PLUS:
4735 case BC_LEX_OP_REL_EQ:
4736 case BC_LEX_OP_REL_LE:
4737 case BC_LEX_OP_REL_GE:
4738 case BC_LEX_OP_REL_NE:
4739 case BC_LEX_OP_REL_LT:
4740 case BC_LEX_OP_REL_GT:
4741 case BC_LEX_OP_BOOL_NOT:
4742 case BC_LEX_OP_BOOL_OR:
4743 case BC_LEX_OP_BOOL_AND:
4745 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4746 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4748 return bc_error_bad_expression();
4751 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4752 prev = BC_PARSE_TOKEN_INST(t);
4753 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4754 rprn = get_token = false;
4755 bin_last = t != BC_LEX_OP_BOOL_NOT;
4762 if (BC_PARSE_LEAF(prev, rprn))
4763 return bc_error_bad_expression();
4765 paren_expr = rprn = bin_last = false;
4767 bc_vec_push(&p->ops, &t);
4774 if (bin_last || prev == BC_INST_BOOL_NOT)
4775 return bc_error_bad_expression();
4778 s = BC_STATUS_SUCCESS;
4783 else if (!paren_expr)
4784 return BC_STATUS_PARSE_EMPTY_EXP;
4787 paren_expr = rprn = true;
4788 get_token = bin_last = false;
4790 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4797 if (BC_PARSE_LEAF(prev, rprn))
4798 return bc_error_bad_expression();
4800 rprn = get_token = bin_last = false;
4801 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4809 if (BC_PARSE_LEAF(prev, rprn))
4810 return bc_error_bad_expression();
4811 bc_parse_number(p, &prev, &nexprs);
4812 paren_expr = get_token = true;
4813 rprn = bin_last = false;
4818 case BC_LEX_KEY_IBASE:
4819 case BC_LEX_KEY_LAST:
4820 case BC_LEX_KEY_OBASE:
4822 if (BC_PARSE_LEAF(prev, rprn))
4823 return bc_error_bad_expression();
4824 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4825 bc_parse_push(p, (char) prev);
4827 paren_expr = get_token = true;
4828 rprn = bin_last = false;
4834 case BC_LEX_KEY_LENGTH:
4835 case BC_LEX_KEY_SQRT:
4837 if (BC_PARSE_LEAF(prev, rprn))
4838 return bc_error_bad_expression();
4839 s = bc_parse_builtin(p, t, flags, &prev);
4841 rprn = get_token = bin_last = false;
4847 case BC_LEX_KEY_READ:
4849 if (BC_PARSE_LEAF(prev, rprn))
4850 return bc_error_bad_expression();
4851 else if (flags & BC_PARSE_NOREAD)
4852 s = bc_error_nested_read_call();
4854 s = bc_parse_read(p);
4857 rprn = get_token = bin_last = false;
4859 prev = BC_INST_READ;
4864 case BC_LEX_KEY_SCALE:
4866 if (BC_PARSE_LEAF(prev, rprn))
4867 return bc_error_bad_expression();
4868 s = bc_parse_scale(p, &prev, flags);
4870 rprn = get_token = bin_last = false;
4872 prev = BC_INST_SCALE;
4879 s = bc_error_bad_token();
4884 if (!s && get_token) s = bc_lex_next(&p->l);
4888 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4890 while (p->ops.len > ops_bgn) {
4892 top = BC_PARSE_TOP_OP(p);
4893 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4895 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4896 return bc_error_bad_expression();
4898 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4900 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4901 bc_vec_pop(&p->ops);
4904 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4905 return bc_error_bad_expression();
4907 for (i = 0; i < next.len; ++i)
4908 if (t == next.tokens[i])
4910 return bc_error_bad_expression();
4913 if (!(flags & BC_PARSE_REL) && nrelops) {
4914 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
4917 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4918 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4922 if (flags & BC_PARSE_PRINT) {
4923 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4924 bc_parse_push(p, BC_INST_POP);
4930 static void bc_parse_init(BcParse *p, size_t func)
4932 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4935 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4937 return bc_parse_expr(p, flags, bc_parse_next_read);
4942 static BcStatus dc_parse_register(BcParse *p)
4947 s = bc_lex_next(&p->l);
4949 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
4951 name = xstrdup(p->l.t.v.v);
4952 bc_parse_pushName(p, name);
4957 static BcStatus dc_parse_string(BcParse *p)
4959 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4960 size_t idx, len = G.prog.strs.len;
4962 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4965 str = xstrdup(p->l.t.v.v);
4966 bc_parse_push(p, BC_INST_STR);
4967 bc_parse_pushIndex(p, len);
4968 bc_vec_push(&G.prog.strs, &str);
4969 bc_parse_addFunc(p, name, &idx);
4971 return bc_lex_next(&p->l);
4974 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4978 bc_parse_push(p, inst);
4980 s = dc_parse_register(p);
4985 bc_parse_push(p, BC_INST_SWAP);
4986 bc_parse_push(p, BC_INST_ASSIGN);
4987 bc_parse_push(p, BC_INST_POP);
4990 return bc_lex_next(&p->l);
4993 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4997 bc_parse_push(p, inst);
4998 bc_parse_push(p, BC_INST_EXEC_COND);
5000 s = dc_parse_register(p);
5003 s = bc_lex_next(&p->l);
5006 if (p->l.t.t == BC_LEX_ELSE) {
5007 s = dc_parse_register(p);
5009 s = bc_lex_next(&p->l);
5012 bc_parse_push(p, BC_PARSE_STREND);
5017 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5019 BcStatus s = BC_STATUS_SUCCESS;
5022 bool assign, get_token = false;
5026 case BC_LEX_OP_REL_EQ:
5027 case BC_LEX_OP_REL_LE:
5028 case BC_LEX_OP_REL_GE:
5029 case BC_LEX_OP_REL_NE:
5030 case BC_LEX_OP_REL_LT:
5031 case BC_LEX_OP_REL_GT:
5033 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5040 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5046 s = dc_parse_string(p);
5053 if (t == BC_LEX_NEG) {
5054 s = bc_lex_next(&p->l);
5056 if (p->l.t.t != BC_LEX_NUMBER)
5057 return bc_error_bad_token();
5060 bc_parse_number(p, &prev, &p->nbraces);
5062 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5068 case BC_LEX_KEY_READ:
5070 if (flags & BC_PARSE_NOREAD)
5071 s = bc_error_nested_read_call();
5073 bc_parse_push(p, BC_INST_READ);
5078 case BC_LEX_OP_ASSIGN:
5079 case BC_LEX_STORE_PUSH:
5081 assign = t == BC_LEX_OP_ASSIGN;
5082 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5083 s = dc_parse_mem(p, inst, true, assign);
5088 case BC_LEX_LOAD_POP:
5090 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5091 s = dc_parse_mem(p, inst, true, false);
5095 case BC_LEX_STORE_IBASE:
5096 case BC_LEX_STORE_SCALE:
5097 case BC_LEX_STORE_OBASE:
5099 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5100 s = dc_parse_mem(p, inst, false, true);
5106 s = bc_error_bad_token();
5112 if (!s && get_token) s = bc_lex_next(&p->l);
5117 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5119 BcStatus s = BC_STATUS_SUCCESS;
5123 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5125 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5127 inst = dc_parse_insts[t];
5129 if (inst != BC_INST_INVALID) {
5130 bc_parse_push(p, inst);
5131 s = bc_lex_next(&p->l);
5134 s = dc_parse_token(p, t, flags);
5137 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5138 bc_parse_push(p, BC_INST_POP_EXEC);
5143 static BcStatus dc_parse_parse(BcParse *p)
5147 if (p->l.t.t == BC_LEX_EOF)
5148 s = bc_error("end of file");
5150 s = dc_parse_expr(p, 0);
5152 if (s || G_interrupt) {
5154 s = BC_STATUS_FAILURE;
5160 static void dc_parse_init(BcParse *p, size_t func)
5162 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5166 static void common_parse_init(BcParse *p, size_t func)
5169 bc_parse_init(p, func);
5171 dc_parse_init(p, func);
5175 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5178 return bc_parse_expression(p, flags);
5180 return dc_parse_expr(p, flags);
5184 static BcVec* bc_program_search(char *id, bool var)
5192 v = var ? &G.prog.vars : &G.prog.arrs;
5193 map = var ? &G.prog.var_map : &G.prog.arr_map;
5197 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5200 bc_array_init(&data.v, var);
5201 bc_vec_push(v, &data.v);
5204 ptr = bc_vec_item(map, i);
5205 if (new) ptr->name = xstrdup(e.name);
5206 return bc_vec_item(v, ptr->idx);
5209 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5211 BcStatus s = BC_STATUS_SUCCESS;
5216 case BC_RESULT_TEMP:
5217 case BC_RESULT_IBASE:
5218 case BC_RESULT_SCALE:
5219 case BC_RESULT_OBASE:
5225 case BC_RESULT_CONSTANT:
5227 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5228 size_t base_t, len = strlen(*str);
5231 bc_num_init(&r->d.n, len);
5233 hex = hex && len == 1;
5234 base = hex ? &G.prog.hexb : &G.prog.ib;
5235 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5236 s = bc_num_parse(&r->d.n, *str, base, base_t);
5239 bc_num_free(&r->d.n);
5244 r->t = BC_RESULT_TEMP;
5250 case BC_RESULT_ARRAY:
5251 case BC_RESULT_ARRAY_ELEM:
5255 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5257 if (r->t == BC_RESULT_ARRAY_ELEM) {
5259 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5260 *num = bc_vec_item(v, r->d.id.idx);
5263 *num = bc_vec_top(v);
5268 case BC_RESULT_LAST:
5270 *num = &G.prog.last;
5284 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5285 BcResult **r, BcNum **rn, bool assign)
5289 BcResultType lt, rt;
5291 if (!BC_PROG_STACK(&G.prog.results, 2))
5292 return bc_error_stack_has_too_few_elements();
5294 *r = bc_vec_item_rev(&G.prog.results, 0);
5295 *l = bc_vec_item_rev(&G.prog.results, 1);
5299 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5301 s = bc_program_num(*l, ln, false);
5303 s = bc_program_num(*r, rn, hex);
5306 // We run this again under these conditions in case any vector has been
5307 // reallocated out from under the BcNums or arrays we had.
5308 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5309 s = bc_program_num(*l, ln, false);
5313 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5314 return bc_error_variable_is_wrong_type();
5315 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5316 return bc_error_variable_is_wrong_type();
5321 static void bc_program_binOpRetire(BcResult *r)
5323 r->t = BC_RESULT_TEMP;
5324 bc_vec_pop(&G.prog.results);
5325 bc_vec_pop(&G.prog.results);
5326 bc_vec_push(&G.prog.results, r);
5329 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5333 if (!BC_PROG_STACK(&G.prog.results, 1))
5334 return bc_error_stack_has_too_few_elements();
5335 *r = bc_vec_top(&G.prog.results);
5337 s = bc_program_num(*r, n, false);
5340 if (!BC_PROG_NUM((*r), (*n)))
5341 return bc_error_variable_is_wrong_type();
5346 static void bc_program_retire(BcResult *r, BcResultType t)
5349 bc_vec_pop(&G.prog.results);
5350 bc_vec_push(&G.prog.results, r);
5353 static BcStatus bc_program_op(char inst)
5356 BcResult *opd1, *opd2, res;
5357 BcNum *n1, *n2 = NULL;
5359 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5361 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5363 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5365 bc_program_binOpRetire(&res);
5370 bc_num_free(&res.d.n);
5374 static BcStatus bc_program_read(void)
5376 const char *sv_file;
5382 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5384 for (i = 0; i < G.prog.stack.len; ++i) {
5385 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5386 if (ip_ptr->func == BC_PROG_READ)
5387 return bc_error_nested_read_call();
5390 bc_vec_pop_all(&f->code);
5391 bc_char_vec_init(&buf);
5393 sv_file = G.prog.file;
5396 s = bc_read_line(&buf, "read> ");
5399 common_parse_init(&parse, BC_PROG_READ);
5400 bc_lex_file(&parse.l);
5402 s = bc_parse_text(&parse, buf.v);
5403 if (s) goto exec_err;
5404 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5405 if (s) goto exec_err;
5407 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5408 s = bc_error("bad read() expression");
5412 ip.func = BC_PROG_READ;
5414 ip.len = G.prog.results.len;
5416 // Update this pointer, just in case.
5417 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5419 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5420 bc_vec_push(&G.prog.stack, &ip);
5423 G.prog.file = sv_file;
5424 bc_parse_free(&parse);
5430 static size_t bc_program_index(char *code, size_t *bgn)
5432 char amt = code[(*bgn)++], i = 0;
5435 for (; i < amt; ++i, ++(*bgn))
5436 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5441 static char *bc_program_name(char *code, size_t *bgn)
5444 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5446 s = xmalloc(ptr - str + 1);
5449 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5457 static void bc_program_printString(const char *str, size_t *nchars)
5459 size_t i, len = strlen(str);
5468 for (i = 0; i < len; ++i, ++(*nchars)) {
5472 if (c != '\\' || i == len - 1)
5532 // Just print the backslash and following character.
5543 static BcStatus bc_program_print(char inst, size_t idx)
5545 BcStatus s = BC_STATUS_SUCCESS;
5550 bool pop = inst != BC_INST_PRINT;
5552 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5553 return bc_error_stack_has_too_few_elements();
5555 r = bc_vec_item_rev(&G.prog.results, idx);
5556 s = bc_program_num(r, &num, false);
5559 if (BC_PROG_NUM(r, num)) {
5560 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5561 if (!s) bc_num_copy(&G.prog.last, num);
5565 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5566 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5568 if (inst == BC_INST_PRINT_STR) {
5569 for (i = 0, len = strlen(str); i < len; ++i) {
5572 if (c == '\n') G.prog.nchars = SIZE_MAX;
5577 bc_program_printString(str, &G.prog.nchars);
5578 if (inst == BC_INST_PRINT) bb_putchar('\n');
5582 if (!s && pop) bc_vec_pop(&G.prog.results);
5587 static BcStatus bc_program_negate(void)
5593 s = bc_program_prep(&ptr, &num);
5596 bc_num_init(&res.d.n, num->len);
5597 bc_num_copy(&res.d.n, num);
5598 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5600 bc_program_retire(&res, BC_RESULT_TEMP);
5605 static BcStatus bc_program_logical(char inst)
5608 BcResult *opd1, *opd2, res;
5613 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5615 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5617 if (inst == BC_INST_BOOL_AND)
5618 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5619 else if (inst == BC_INST_BOOL_OR)
5620 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5623 cmp = bc_num_cmp(n1, n2);
5627 case BC_INST_REL_EQ:
5633 case BC_INST_REL_LE:
5639 case BC_INST_REL_GE:
5645 case BC_INST_REL_NE:
5651 case BC_INST_REL_LT:
5657 case BC_INST_REL_GT:
5665 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5667 bc_program_binOpRetire(&res);
5673 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5679 memset(&n2, 0, sizeof(BcNum));
5680 n2.rdx = res.d.id.idx = r->d.id.idx;
5681 res.t = BC_RESULT_STR;
5684 if (!BC_PROG_STACK(&G.prog.results, 2))
5685 return bc_error_stack_has_too_few_elements();
5687 bc_vec_pop(&G.prog.results);
5690 bc_vec_pop(&G.prog.results);
5692 bc_vec_push(&G.prog.results, &res);
5693 bc_vec_push(v, &n2);
5695 return BC_STATUS_SUCCESS;
5699 static BcStatus bc_program_copyToVar(char *name, bool var)
5706 if (!BC_PROG_STACK(&G.prog.results, 1))
5707 return bc_error_stack_has_too_few_elements();
5709 ptr = bc_vec_top(&G.prog.results);
5710 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5711 return bc_error_variable_is_wrong_type();
5712 v = bc_program_search(name, var);
5715 if (ptr->t == BC_RESULT_STR && !var)
5716 return bc_error_variable_is_wrong_type();
5717 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5720 s = bc_program_num(ptr, &n, false);
5723 // Do this once more to make sure that pointers were not invalidated.
5724 v = bc_program_search(name, var);
5727 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5728 bc_num_copy(&r.d.n, n);
5731 bc_array_init(&r.d.v, true);
5732 bc_array_copy(&r.d.v, (BcVec *) n);
5735 bc_vec_push(v, &r.d);
5736 bc_vec_pop(&G.prog.results);
5741 static BcStatus bc_program_assign(char inst)
5744 BcResult *left, *right, res;
5745 BcNum *l = NULL, *r = NULL;
5746 unsigned long val, max;
5747 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5749 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5752 ib = left->t == BC_RESULT_IBASE;
5753 sc = left->t == BC_RESULT_SCALE;
5757 if (right->t == BC_RESULT_STR) {
5761 if (left->t != BC_RESULT_VAR)
5762 return bc_error_variable_is_wrong_type();
5763 v = bc_program_search(left->d.id.name, true);
5765 return bc_program_assignStr(right, v, false);
5769 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5770 return bc_error("bad assignment:"
5771 " left side must be scale,"
5772 " ibase, obase, last, var,"
5777 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5778 return bc_error("divide by zero");
5783 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5790 if (ib || sc || left->t == BC_RESULT_OBASE) {
5791 static const char *const msg[] = {
5792 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5793 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5794 "?1", //BC_RESULT_LAST
5795 "?2", //BC_RESULT_CONSTANT
5796 "?3", //BC_RESULT_ONE
5797 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5801 s = bc_num_ulong(l, &val);
5804 s = left->t - BC_RESULT_IBASE;
5807 ptr = &G.prog.scale;
5810 if (val < BC_NUM_MIN_BASE)
5811 return bc_error(msg[s]);
5812 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5813 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5817 return bc_error(msg[s]);
5819 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5821 *ptr = (size_t) val;
5822 s = BC_STATUS_SUCCESS;
5825 bc_num_init(&res.d.n, l->len);
5826 bc_num_copy(&res.d.n, l);
5827 bc_program_binOpRetire(&res);
5833 #define bc_program_pushVar(code, bgn, pop, copy) \
5834 bc_program_pushVar(code, bgn)
5835 // for bc, 'pop' and 'copy' are always false
5837 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5838 bool pop, bool copy)
5840 BcStatus s = BC_STATUS_SUCCESS;
5842 char *name = bc_program_name(code, bgn);
5844 r.t = BC_RESULT_VAR;
5849 BcVec *v = bc_program_search(name, true);
5850 BcNum *num = bc_vec_top(v);
5854 if (!BC_PROG_STACK(v, 2 - copy)) {
5856 return bc_error_stack_has_too_few_elements();
5862 if (!BC_PROG_STR(num)) {
5864 r.t = BC_RESULT_TEMP;
5866 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5867 bc_num_copy(&r.d.n, num);
5870 r.t = BC_RESULT_STR;
5871 r.d.id.idx = num->rdx;
5874 if (!copy) bc_vec_pop(v);
5879 bc_vec_push(&G.prog.results, &r);
5884 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5887 BcStatus s = BC_STATUS_SUCCESS;
5891 r.d.id.name = bc_program_name(code, bgn);
5893 if (inst == BC_INST_ARRAY) {
5894 r.t = BC_RESULT_ARRAY;
5895 bc_vec_push(&G.prog.results, &r);
5902 s = bc_program_prep(&operand, &num);
5904 s = bc_num_ulong(num, &temp);
5907 if (temp > BC_MAX_DIM) {
5908 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5912 r.d.id.idx = (size_t) temp;
5913 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5917 if (s) free(r.d.id.name);
5922 static BcStatus bc_program_incdec(char inst)
5925 BcResult *ptr, res, copy;
5929 s = bc_program_prep(&ptr, &num);
5932 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5933 copy.t = BC_RESULT_TEMP;
5934 bc_num_init(©.d.n, num->len);
5935 bc_num_copy(©.d.n, num);
5938 res.t = BC_RESULT_ONE;
5939 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5940 BC_INST_ASSIGN_PLUS :
5941 BC_INST_ASSIGN_MINUS;
5943 bc_vec_push(&G.prog.results, &res);
5944 bc_program_assign(inst);
5946 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5947 bc_vec_pop(&G.prog.results);
5948 bc_vec_push(&G.prog.results, ©);
5954 static BcStatus bc_program_call(char *code, size_t *idx)
5956 BcStatus s = BC_STATUS_SUCCESS;
5958 size_t i, nparams = bc_program_index(code, idx);
5965 ip.func = bc_program_index(code, idx);
5966 func = bc_vec_item(&G.prog.fns, ip.func);
5968 if (func->code.len == 0) {
5969 return bc_error("undefined function");
5971 if (nparams != func->nparams) {
5972 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
5974 ip.len = G.prog.results.len - nparams;
5976 for (i = 0; i < nparams; ++i) {
5978 a = bc_vec_item(&func->autos, nparams - 1 - i);
5979 arg = bc_vec_top(&G.prog.results);
5981 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5982 return bc_error_variable_is_wrong_type();
5984 s = bc_program_copyToVar(a->name, a->idx);
5988 for (; i < func->autos.len; ++i) {
5991 a = bc_vec_item(&func->autos, i);
5992 v = bc_program_search(a->name, a->idx);
5995 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5996 bc_vec_push(v, ¶m.n);
5999 bc_array_init(¶m.v, true);
6000 bc_vec_push(v, ¶m.v);
6004 bc_vec_push(&G.prog.stack, &ip);
6006 return BC_STATUS_SUCCESS;
6009 static BcStatus bc_program_return(char inst)
6015 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6017 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6018 return bc_error_stack_has_too_few_elements();
6020 f = bc_vec_item(&G.prog.fns, ip->func);
6021 res.t = BC_RESULT_TEMP;
6023 if (inst == BC_INST_RET) {
6026 BcResult *operand = bc_vec_top(&G.prog.results);
6028 s = bc_program_num(operand, &num, false);
6030 bc_num_init(&res.d.n, num->len);
6031 bc_num_copy(&res.d.n, num);
6034 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6035 bc_num_zero(&res.d.n);
6038 // We need to pop arguments as well, so this takes that into account.
6039 for (i = 0; i < f->autos.len; ++i) {
6042 BcId *a = bc_vec_item(&f->autos, i);
6044 v = bc_program_search(a->name, a->idx);
6048 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6049 bc_vec_push(&G.prog.results, &res);
6050 bc_vec_pop(&G.prog.stack);
6052 return BC_STATUS_SUCCESS;
6056 static unsigned long bc_program_scale(BcNum *n)
6058 return (unsigned long) n->rdx;
6061 static unsigned long bc_program_len(BcNum *n)
6063 unsigned long len = n->len;
6066 if (n->rdx != n->len) return len;
6067 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6072 static BcStatus bc_program_builtin(char inst)
6078 bool len = inst == BC_INST_LENGTH;
6080 if (!BC_PROG_STACK(&G.prog.results, 1))
6081 return bc_error_stack_has_too_few_elements();
6082 opnd = bc_vec_top(&G.prog.results);
6084 s = bc_program_num(opnd, &num, false);
6088 if (!BC_PROG_NUM(opnd, num) && !len)
6089 return bc_error_variable_is_wrong_type();
6092 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6094 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6096 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6097 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6101 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6104 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6106 str = bc_vec_item(&G.prog.strs, idx);
6107 bc_num_ulong2num(&res.d.n, strlen(*str));
6111 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6112 bc_num_ulong2num(&res.d.n, f(num));
6115 bc_program_retire(&res, BC_RESULT_TEMP);
6121 static BcStatus bc_program_divmod(void)
6124 BcResult *opd1, *opd2, res, res2;
6125 BcNum *n1, *n2 = NULL;
6127 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6130 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6131 bc_num_init(&res2.d.n, n2->len);
6133 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6136 bc_program_binOpRetire(&res2);
6137 res.t = BC_RESULT_TEMP;
6138 bc_vec_push(&G.prog.results, &res);
6143 bc_num_free(&res2.d.n);
6144 bc_num_free(&res.d.n);
6148 static BcStatus bc_program_modexp(void)
6151 BcResult *r1, *r2, *r3, res;
6152 BcNum *n1, *n2, *n3;
6154 if (!BC_PROG_STACK(&G.prog.results, 3))
6155 return bc_error_stack_has_too_few_elements();
6156 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6159 r1 = bc_vec_item_rev(&G.prog.results, 2);
6160 s = bc_program_num(r1, &n1, false);
6162 if (!BC_PROG_NUM(r1, n1))
6163 return bc_error_variable_is_wrong_type();
6165 // Make sure that the values have their pointers updated, if necessary.
6166 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6168 if (r1->t == r2->t) {
6169 s = bc_program_num(r2, &n2, false);
6173 if (r1->t == r3->t) {
6174 s = bc_program_num(r3, &n3, false);
6179 bc_num_init(&res.d.n, n3->len);
6180 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6183 bc_vec_pop(&G.prog.results);
6184 bc_program_binOpRetire(&res);
6189 bc_num_free(&res.d.n);
6193 static void bc_program_stackLen(void)
6196 size_t len = G.prog.results.len;
6198 res.t = BC_RESULT_TEMP;
6200 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6201 bc_num_ulong2num(&res.d.n, len);
6202 bc_vec_push(&G.prog.results, &res);
6205 static BcStatus bc_program_asciify(void)
6209 BcNum *num = NULL, n;
6210 char *str, *str2, c;
6211 size_t len = G.prog.strs.len, idx;
6214 if (!BC_PROG_STACK(&G.prog.results, 1))
6215 return bc_error_stack_has_too_few_elements();
6216 r = bc_vec_top(&G.prog.results);
6218 s = bc_program_num(r, &num, false);
6221 if (BC_PROG_NUM(r, num)) {
6223 bc_num_init(&n, BC_NUM_DEF_SIZE);
6224 bc_num_copy(&n, num);
6225 bc_num_truncate(&n, n.rdx);
6227 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6228 if (s) goto num_err;
6229 s = bc_num_ulong(&n, &val);
6230 if (s) goto num_err;
6237 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6238 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6246 str2 = xstrdup(str);
6247 bc_program_addFunc(str2, &idx);
6249 if (idx != len + BC_PROG_REQ_FUNCS) {
6251 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6252 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6261 bc_vec_push(&G.prog.strs, &str);
6263 res.t = BC_RESULT_STR;
6265 bc_vec_pop(&G.prog.results);
6266 bc_vec_push(&G.prog.results, &res);
6268 return BC_STATUS_SUCCESS;
6275 static BcStatus bc_program_printStream(void)
6283 if (!BC_PROG_STACK(&G.prog.results, 1))
6284 return bc_error_stack_has_too_few_elements();
6285 r = bc_vec_top(&G.prog.results);
6287 s = bc_program_num(r, &n, false);
6290 if (BC_PROG_NUM(r, n))
6291 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6293 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6294 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6301 static BcStatus bc_program_nquit(void)
6308 s = bc_program_prep(&opnd, &num);
6310 s = bc_num_ulong(num, &val);
6313 bc_vec_pop(&G.prog.results);
6315 if (G.prog.stack.len < val)
6316 return bc_error_stack_has_too_few_elements();
6317 if (G.prog.stack.len == val)
6320 bc_vec_npop(&G.prog.stack, val);
6325 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6328 BcStatus s = BC_STATUS_SUCCESS;
6338 if (!BC_PROG_STACK(&G.prog.results, 1))
6339 return bc_error_stack_has_too_few_elements();
6341 r = bc_vec_top(&G.prog.results);
6345 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6347 if (code[*bgn] == BC_PARSE_STREND)
6350 else_name = bc_program_name(code, bgn);
6352 exec = r->d.n.len != 0;
6356 else if (else_name != NULL) {
6363 v = bc_program_search(name, true);
6370 if (!exec) goto exit;
6371 if (!BC_PROG_STR(n)) {
6372 s = bc_error_variable_is_wrong_type();
6380 if (r->t == BC_RESULT_STR)
6382 else if (r->t == BC_RESULT_VAR) {
6383 s = bc_program_num(r, &n, false);
6384 if (s || !BC_PROG_STR(n)) goto exit;
6391 fidx = sidx + BC_PROG_REQ_FUNCS;
6393 str = bc_vec_item(&G.prog.strs, sidx);
6394 f = bc_vec_item(&G.prog.fns, fidx);
6396 if (f->code.len == 0) {
6397 common_parse_init(&prs, fidx);
6398 s = bc_parse_text(&prs, *str);
6400 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6403 if (prs.l.t.t != BC_LEX_EOF) {
6404 s = bc_error_bad_expression();
6408 bc_parse_free(&prs);
6412 ip.len = G.prog.results.len;
6415 bc_vec_pop(&G.prog.results);
6416 bc_vec_push(&G.prog.stack, &ip);
6418 return BC_STATUS_SUCCESS;
6421 bc_parse_free(&prs);
6422 f = bc_vec_item(&G.prog.fns, fidx);
6423 bc_vec_pop_all(&f->code);
6425 bc_vec_pop(&G.prog.results);
6430 static void bc_program_pushGlobal(char inst)
6435 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6436 if (inst == BC_INST_IBASE)
6437 val = (unsigned long) G.prog.ib_t;
6438 else if (inst == BC_INST_SCALE)
6439 val = (unsigned long) G.prog.scale;
6441 val = (unsigned long) G.prog.ob_t;
6443 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6444 bc_num_ulong2num(&res.d.n, val);
6445 bc_vec_push(&G.prog.results, &res);
6448 static void bc_program_addFunc(char *name, size_t *idx)
6450 BcId entry, *entry_ptr;
6455 entry.idx = G.prog.fns.len;
6457 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6458 if (!inserted) free(name);
6460 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6461 *idx = entry_ptr->idx;
6465 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6467 // We need to reset these, so the function can be repopulated.
6469 bc_vec_pop_all(&func->autos);
6470 bc_vec_pop_all(&func->code);
6471 bc_vec_pop_all(&func->labels);
6475 bc_vec_push(&G.prog.fns, &f);
6479 // Called when parsing or execution detects a failure,
6480 // resets execution structures.
6481 static void bc_program_reset(void)
6486 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6487 bc_vec_pop_all(&G.prog.results);
6489 f = bc_vec_item(&G.prog.fns, 0);
6490 ip = bc_vec_top(&G.prog.stack);
6491 ip->idx = f->code.len;
6493 // If !tty, no need to check for ^C: we don't have ^C handler,
6494 // we would be killed by a signal and won't reach this place
6497 static BcStatus bc_program_exec(void)
6499 BcStatus s = BC_STATUS_SUCCESS;
6503 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6504 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6505 char *code = func->code.v;
6508 while (!s && ip->idx < func->code.len) {
6510 char inst = code[(ip->idx)++];
6515 case BC_INST_JUMP_ZERO:
6517 s = bc_program_prep(&ptr, &num);
6519 cond = !bc_num_cmp(num, &G.prog.zero);
6520 bc_vec_pop(&G.prog.results);
6526 idx = bc_program_index(code, &ip->idx);
6527 addr = bc_vec_item(&func->labels, idx);
6528 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6534 s = bc_program_call(code, &ip->idx);
6538 case BC_INST_INC_PRE:
6539 case BC_INST_DEC_PRE:
6540 case BC_INST_INC_POST:
6541 case BC_INST_DEC_POST:
6543 s = bc_program_incdec(inst);
6556 s = bc_program_return(inst);
6560 case BC_INST_BOOL_OR:
6561 case BC_INST_BOOL_AND:
6563 case BC_INST_REL_EQ:
6564 case BC_INST_REL_LE:
6565 case BC_INST_REL_GE:
6566 case BC_INST_REL_NE:
6567 case BC_INST_REL_LT:
6568 case BC_INST_REL_GT:
6570 s = bc_program_logical(inst);
6576 s = bc_program_read();
6582 s = bc_program_pushVar(code, &ip->idx, false, false);
6586 case BC_INST_ARRAY_ELEM:
6589 s = bc_program_pushArray(code, &ip->idx, inst);
6595 r.t = BC_RESULT_LAST;
6596 bc_vec_push(&G.prog.results, &r);
6604 bc_program_pushGlobal(inst);
6608 case BC_INST_SCALE_FUNC:
6609 case BC_INST_LENGTH:
6612 s = bc_program_builtin(inst);
6618 r.t = BC_RESULT_CONSTANT;
6619 r.d.id.idx = bc_program_index(code, &ip->idx);
6620 bc_vec_push(&G.prog.results, &r);
6626 if (!BC_PROG_STACK(&G.prog.results, 1))
6627 s = bc_error_stack_has_too_few_elements();
6629 bc_vec_pop(&G.prog.results);
6633 case BC_INST_POP_EXEC:
6635 bc_vec_pop(&G.prog.stack);
6640 case BC_INST_PRINT_POP:
6641 case BC_INST_PRINT_STR:
6643 s = bc_program_print(inst, 0);
6649 r.t = BC_RESULT_STR;
6650 r.d.id.idx = bc_program_index(code, &ip->idx);
6651 bc_vec_push(&G.prog.results, &r);
6656 case BC_INST_MULTIPLY:
6657 case BC_INST_DIVIDE:
6658 case BC_INST_MODULUS:
6662 s = bc_program_op(inst);
6666 case BC_INST_BOOL_NOT:
6668 s = bc_program_prep(&ptr, &num);
6671 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6672 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6673 bc_program_retire(&r, BC_RESULT_TEMP);
6680 s = bc_program_negate();
6685 case BC_INST_ASSIGN_POWER:
6686 case BC_INST_ASSIGN_MULTIPLY:
6687 case BC_INST_ASSIGN_DIVIDE:
6688 case BC_INST_ASSIGN_MODULUS:
6689 case BC_INST_ASSIGN_PLUS:
6690 case BC_INST_ASSIGN_MINUS:
6692 case BC_INST_ASSIGN:
6694 s = bc_program_assign(inst);
6698 case BC_INST_MODEXP:
6700 s = bc_program_modexp();
6704 case BC_INST_DIVMOD:
6706 s = bc_program_divmod();
6710 case BC_INST_EXECUTE:
6711 case BC_INST_EXEC_COND:
6713 cond = inst == BC_INST_EXEC_COND;
6714 s = bc_program_execStr(code, &ip->idx, cond);
6718 case BC_INST_PRINT_STACK:
6720 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6721 s = bc_program_print(BC_INST_PRINT, idx);
6725 case BC_INST_CLEAR_STACK:
6727 bc_vec_pop_all(&G.prog.results);
6731 case BC_INST_STACK_LEN:
6733 bc_program_stackLen();
6737 case BC_INST_DUPLICATE:
6739 if (!BC_PROG_STACK(&G.prog.results, 1))
6740 return bc_error_stack_has_too_few_elements();
6741 ptr = bc_vec_top(&G.prog.results);
6742 bc_result_copy(&r, ptr);
6743 bc_vec_push(&G.prog.results, &r);
6751 if (!BC_PROG_STACK(&G.prog.results, 2))
6752 return bc_error_stack_has_too_few_elements();
6754 ptr = bc_vec_item_rev(&G.prog.results, 0);
6755 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6756 memcpy(&r, ptr, sizeof(BcResult));
6757 memcpy(ptr, ptr2, sizeof(BcResult));
6758 memcpy(ptr2, &r, sizeof(BcResult));
6763 case BC_INST_ASCIIFY:
6765 s = bc_program_asciify();
6769 case BC_INST_PRINT_STREAM:
6771 s = bc_program_printStream();
6776 case BC_INST_PUSH_VAR:
6778 bool copy = inst == BC_INST_LOAD;
6779 s = bc_program_pushVar(code, &ip->idx, true, copy);
6783 case BC_INST_PUSH_TO_VAR:
6785 char *name = bc_program_name(code, &ip->idx);
6786 s = bc_program_copyToVar(name, true);
6793 if (G.prog.stack.len <= 2)
6795 bc_vec_npop(&G.prog.stack, 2);
6801 s = bc_program_nquit();
6807 if (s || G_interrupt) {
6812 // If the stack has changed, pointers may be invalid.
6813 ip = bc_vec_top(&G.prog.stack);
6814 func = bc_vec_item(&G.prog.fns, ip->func);
6815 code = func->code.v;
6821 static void bc_vm_info(void)
6823 printf("%s "BB_VER"\n"
6824 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6825 "Report bugs at: https://github.com/gavinhoward/bc\n"
6826 "This is free software with ABSOLUTELY NO WARRANTY\n"
6831 static void bc_vm_envArgs(void)
6833 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6836 char *env_args = getenv(bc_args_env_name), *buf;
6838 if (!env_args) return;
6840 G.env_args = xstrdup(env_args);
6843 bc_vec_init(&v, sizeof(char *), NULL);
6844 bc_vec_push(&v, &bc_args_env_name);
6847 if (!isspace(*buf)) {
6848 bc_vec_push(&v, &buf);
6849 while (*buf != 0 && !isspace(*buf)) ++buf;
6850 if (*buf != 0) (*(buf++)) = '\0';
6856 bc_args((int) v.len, (char **) v.v);
6862 static size_t bc_vm_envLen(const char *var)
6864 char *lenv = getenv(var);
6865 size_t i, len = BC_NUM_PRINT_WIDTH;
6868 if (!lenv) return len;
6872 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6874 len = (size_t) atoi(lenv) - 1;
6875 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6878 len = BC_NUM_PRINT_WIDTH;
6883 static BcStatus bc_vm_process(const char *text)
6885 BcStatus s = bc_parse_text(&G.prs, text);
6889 while (G.prs.l.t.t != BC_LEX_EOF) {
6890 s = G.prs.parse(&G.prs);
6894 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6895 s = bc_program_exec();
6904 static BcStatus bc_vm_file(const char *file)
6906 const char *sv_file;
6912 data = bc_read_file(file);
6913 if (!data) return bc_error_fmt("file '%s' is not text", file);
6915 sv_file = G.prog.file;
6917 bc_lex_file(&G.prs.l);
6918 s = bc_vm_process(data);
6921 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6922 ip = bc_vec_item(&G.prog.stack, 0);
6924 if (main_func->code.len < ip->idx)
6925 s = bc_error_fmt("file '%s' is not executable", file);
6928 G.prog.file = sv_file;
6933 static BcStatus bc_vm_stdin(void)
6937 size_t len, i, str = 0;
6938 bool comment = false;
6941 bc_lex_file(&G.prs.l);
6943 bc_char_vec_init(&buffer);
6944 bc_char_vec_init(&buf);
6945 bc_vec_pushZeroByte(&buffer);
6947 // This loop is complex because the vm tries not to send any lines that end
6948 // with a backslash to the parser. The reason for that is because the parser
6949 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6950 // case, and for strings and comments, the parser will expect more stuff.
6951 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6953 char *string = buf.v;
6958 if (str && buf.v[0] == G.send)
6960 else if (buf.v[0] == G.sbgn)
6963 else if (len > 1 || comment) {
6965 for (i = 0; i < len; ++i) {
6967 bool notend = len > i + 1;
6970 if (i - 1 > len || string[i - 1] != '\\') {
6971 if (G.sbgn == G.send)
6973 else if (c == G.send)
6975 else if (c == G.sbgn)
6979 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6983 else if (c == '*' && notend && comment && string[i + 1] == '/')
6987 if (str || comment || string[len - 2] == '\\') {
6988 bc_vec_concat(&buffer, buf.v);
6993 bc_vec_concat(&buffer, buf.v);
6994 s = bc_vm_process(buffer.v);
6997 fputs("ready for more input\n", stderr);
7000 bc_vec_pop_all(&buffer);
7004 s = bc_error("string end could not be found");
7007 s = bc_error("comment end could not be found");
7011 bc_vec_free(&buffer);
7016 static const char bc_lib[] = {
7019 "\n" "auto b,s,n,r,d,i,p,f,v"
7028 "\n" "scale=scale(x)+1"
7038 "\n" "for(i=2;v!=0;++i){"
7044 "\n" "while((d--)!=0)r*=r"
7047 "\n" "if(n!=0)return(1/r)"
7051 "\n" "auto b,s,r,p,a,q,i,v"
7055 "\n" "r=(1-10^scale)/1"
7066 "\n" "while(x<=0.5){"
7070 "\n" "r=a=(x-1)/(x+1)"
7073 "\n" "for(i=3;v!=0;i+=2){"
7084 "\n" "auto b,s,r,n,a,q,i"
7088 "\n" "scale=1.1*s+2"
7097 "\n" "if(q%2!=0)x=-x"
7101 "\n" "for(i=3;a!=0;i+=2){"
7102 "\n" "a*=q/(i*(i-1))"
7107 "\n" "if(n!=0)return(-r/1)"
7116 "\n" "x=s(2*a(1)+x)"
7122 "\n" "auto b,s,r,n,a,m,t,f,i,u"
7131 "\n" "if(scale<65){"
7132 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7136 "\n" "if(scale<65){"
7137 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7148 "\n" "x=(x-.2)/(1+.2*x)"
7153 "\n" "for(i=3;t!=0;i+=2){"
7160 "\n" "return((m*a+r)/n)"
7162 "\n" "define j(n,x){"
7163 "\n" "auto b,s,o,a,i,v,f"
7171 "\n" "if(n%2==1)o=1"
7174 "\n" "for(i=2;i<=n;++i)a*=i"
7176 "\n" "a=(x^n)/2^n/a"
7179 "\n" "scale=scale+length(a)-scale(a)"
7180 "\n" "for(i=1;v!=0;++i){"
7181 "\n" "v=v*f/i/(n+i)"
7187 "\n" "return(a*r/1)"
7192 static BcStatus bc_vm_exec(void)
7194 BcStatus s = BC_STATUS_SUCCESS;
7198 if (option_mask32 & BC_FLAG_L) {
7200 // We know that internal library is not buggy,
7201 // thus error checking is normally disabled.
7202 # define DEBUG_LIB 0
7203 bc_lex_file(&G.prs.l);
7204 s = bc_parse_text(&G.prs, bc_lib);
7205 if (DEBUG_LIB && s) return s;
7207 while (G.prs.l.t.t != BC_LEX_EOF) {
7208 s = G.prs.parse(&G.prs);
7209 if (DEBUG_LIB && s) return s;
7211 s = bc_program_exec();
7212 if (DEBUG_LIB && s) return s;
7216 for (i = 0; !s && i < G.files.len; ++i)
7217 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7220 fputs("ready for more input\n", stderr);
7223 if (IS_BC || !G.files.len)
7225 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7226 s = bc_vm_process("");
7231 #if ENABLE_FEATURE_CLEAN_UP
7232 static void bc_program_free()
7234 bc_num_free(&G.prog.ib);
7235 bc_num_free(&G.prog.ob);
7236 bc_num_free(&G.prog.hexb);
7238 bc_num_free(&G.prog.strmb);
7240 bc_vec_free(&G.prog.fns);
7241 bc_vec_free(&G.prog.fn_map);
7242 bc_vec_free(&G.prog.vars);
7243 bc_vec_free(&G.prog.var_map);
7244 bc_vec_free(&G.prog.arrs);
7245 bc_vec_free(&G.prog.arr_map);
7246 bc_vec_free(&G.prog.strs);
7247 bc_vec_free(&G.prog.consts);
7248 bc_vec_free(&G.prog.results);
7249 bc_vec_free(&G.prog.stack);
7250 bc_num_free(&G.prog.last);
7251 bc_num_free(&G.prog.zero);
7252 bc_num_free(&G.prog.one);
7255 static void bc_vm_free(void)
7257 bc_vec_free(&G.files);
7259 bc_parse_free(&G.prs);
7264 static void bc_program_init(size_t line_len)
7269 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7270 memset(&ip, 0, sizeof(BcInstPtr));
7272 /* G.prog.nchars = G.prog.scale = 0; - already is */
7273 G.prog.len = line_len;
7275 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7276 bc_num_ten(&G.prog.ib);
7279 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7280 bc_num_ten(&G.prog.ob);
7283 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7284 bc_num_ten(&G.prog.hexb);
7285 G.prog.hexb.num[0] = 6;
7288 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7289 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7292 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7293 bc_num_zero(&G.prog.last);
7295 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7296 bc_num_zero(&G.prog.zero);
7298 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7299 bc_num_one(&G.prog.one);
7301 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7302 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7304 bc_program_addFunc(xstrdup("(main)"), &idx);
7305 bc_program_addFunc(xstrdup("(read)"), &idx);
7307 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7308 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7310 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7311 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7313 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7314 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7315 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7316 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7317 bc_vec_push(&G.prog.stack, &ip);
7320 static void bc_vm_init(const char *env_len)
7322 size_t len = bc_vm_envLen(env_len);
7324 bc_vec_init(&G.files, sizeof(char *), NULL);
7330 bc_program_init(len);
7332 bc_parse_init(&G.prs, BC_PROG_MAIN);
7334 dc_parse_init(&G.prs, BC_PROG_MAIN);
7338 static BcStatus bc_vm_run(int argc, char *argv[],
7339 const char *env_len)
7343 bc_vm_init(env_len);
7344 bc_args(argc, argv);
7346 G.ttyin = isatty(0);
7349 #if ENABLE_FEATURE_BC_SIGNALS
7350 // With SA_RESTART, most system calls will restart
7351 // (IOW: they won't fail with EINTR).
7352 // In particular, this means ^C won't cause
7353 // stdout to get into "error state" if SIGINT hits
7354 // within write() syscall.
7355 // The downside is that ^C while line input is taken
7356 // will only be handled after [Enter] since read()
7357 // from stdin is not interrupted by ^C either,
7358 // it restarts, thus fgetc() does not return on ^C.
7359 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7361 // Without SA_RESTART, this exhibits a bug:
7362 // "while (1) print 1" and try ^C-ing it.
7363 // Intermittently, instead of returning to input line,
7364 // you'll get "output error: Interrupted system call"
7366 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7368 if (!(option_mask32 & BC_FLAG_Q))
7373 #if ENABLE_FEATURE_CLEAN_UP
7380 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7381 int bc_main(int argc, char **argv)
7384 G.sbgn = G.send = '"';
7386 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7391 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7392 int dc_main(int argc, char **argv)
7398 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");