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,
501 typedef BcStatus (*BcLexNext)(struct BcLex *);
503 typedef struct BcLex {
522 #define BC_PARSE_STREND ((char) UCHAR_MAX)
524 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
525 #define bc_parse_updateFunc(p, f) \
526 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
528 #define BC_PARSE_REL (1 << 0)
529 #define BC_PARSE_PRINT (1 << 1)
530 #define BC_PARSE_NOCALL (1 << 2)
531 #define BC_PARSE_NOREAD (1 << 3)
532 #define BC_PARSE_ARRAY (1 << 4)
534 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
535 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
537 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
538 #define BC_PARSE_FUNC_INNER(parse) \
539 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
541 #define BC_PARSE_FLAG_FUNC (1 << 1)
542 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
544 #define BC_PARSE_FLAG_BODY (1 << 2)
545 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
547 #define BC_PARSE_FLAG_LOOP (1 << 3)
548 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
550 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
551 #define BC_PARSE_LOOP_INNER(parse) \
552 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
554 #define BC_PARSE_FLAG_IF (1 << 5)
555 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
557 #define BC_PARSE_FLAG_ELSE (1 << 6)
558 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
560 #define BC_PARSE_FLAG_IF_END (1 << 7)
561 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
563 #define BC_PARSE_CAN_EXEC(parse) \
564 (!(BC_PARSE_TOP_FLAG(parse) & \
565 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
566 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
567 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
569 typedef struct BcOp {
574 typedef struct BcParseNext {
579 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
580 #define BC_PARSE_NEXT(a, ...) \
582 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
589 typedef BcStatus (*BcParseParse)(struct BcParse *);
591 typedef struct BcParse {
614 typedef struct BcLexKeyword {
620 #define BC_LEX_KW_ENTRY(a, b, c) \
622 .name = a, .len = (b), .posix = (c) \
625 static BcStatus bc_lex_token(BcLex *l);
627 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
628 #define BC_PARSE_LEAF(p, rparen) \
629 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
630 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
632 // We can calculate the conversion between tokens and exprs by subtracting the
633 // position of the first operator in the lex enum and adding the position of the
634 // first in the expr enum. Note: This only works for binary operators.
635 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
637 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
643 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
645 static BcStatus dc_lex_token(BcLex *l);
647 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
651 typedef struct BcProgram {
692 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
694 #define BC_PROG_MAIN (0)
695 #define BC_PROG_READ (1)
698 #define BC_PROG_REQ_FUNCS (2)
701 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
702 #define BC_PROG_NUM(r, n) \
703 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
705 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
707 static void bc_program_addFunc(char *name, size_t *idx);
708 static void bc_program_reset(void);
710 #define BC_FLAG_X (1 << 0)
711 #define BC_FLAG_W (1 << 1)
712 #define BC_FLAG_V (1 << 2)
713 #define BC_FLAG_S (1 << 3)
714 #define BC_FLAG_Q (1 << 4)
715 #define BC_FLAG_L (1 << 5)
716 #define BC_FLAG_I (1 << 6)
718 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
719 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
721 #define BC_MAX_OBASE ((unsigned) 999)
722 #define BC_MAX_DIM ((unsigned) INT_MAX)
723 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
724 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
725 #define BC_MAX_NAME BC_MAX_STRING
726 #define BC_MAX_NUM BC_MAX_STRING
727 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
728 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
743 #define G (*ptr_to_globals)
744 #define INIT_G() do { \
745 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
747 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
748 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
749 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
750 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
753 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
755 static void bc_vm_info(void);
758 static const BcLexKeyword bc_lex_kws[20] = {
759 BC_LEX_KW_ENTRY("auto", 4, true),
760 BC_LEX_KW_ENTRY("break", 5, true),
761 BC_LEX_KW_ENTRY("continue", 8, false),
762 BC_LEX_KW_ENTRY("define", 6, true),
763 BC_LEX_KW_ENTRY("else", 4, false),
764 BC_LEX_KW_ENTRY("for", 3, true),
765 BC_LEX_KW_ENTRY("halt", 4, false),
766 BC_LEX_KW_ENTRY("ibase", 5, true),
767 BC_LEX_KW_ENTRY("if", 2, true),
768 BC_LEX_KW_ENTRY("last", 4, false),
769 BC_LEX_KW_ENTRY("length", 6, true),
770 BC_LEX_KW_ENTRY("limits", 6, false),
771 BC_LEX_KW_ENTRY("obase", 5, true),
772 BC_LEX_KW_ENTRY("print", 5, false),
773 BC_LEX_KW_ENTRY("quit", 4, true),
774 BC_LEX_KW_ENTRY("read", 4, false),
775 BC_LEX_KW_ENTRY("return", 6, true),
776 BC_LEX_KW_ENTRY("scale", 5, true),
777 BC_LEX_KW_ENTRY("sqrt", 4, true),
778 BC_LEX_KW_ENTRY("while", 5, true),
781 // This is an array that corresponds to token types. An entry is
782 // true if the token is valid in an expression, false otherwise.
783 static const bool bc_parse_exprs[] = {
784 false, false, true, true, true, true, true, true, true, true, true, true,
785 true, true, true, true, true, true, true, true, true, true, true, true,
786 true, true, true, false, false, true, true, false, false, false, false,
787 false, false, false, true, true, false, false, false, false, false, false,
788 false, true, false, true, true, true, true, false, false, true, false, true,
792 // This is an array of data for operators that correspond to token types.
793 static const BcOp bc_parse_ops[] = {
794 { 0, false }, { 0, false },
797 { 3, true }, { 3, true }, { 3, true },
798 { 4, true }, { 4, true },
799 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
801 { 7, true }, { 7, true },
802 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
803 { 5, false }, { 5, false },
806 // These identify what tokens can come after expressions in certain cases.
807 static const BcParseNext bc_parse_next_expr =
808 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
809 static const BcParseNext bc_parse_next_param =
810 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
811 static const BcParseNext bc_parse_next_print =
812 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
813 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
814 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
815 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
816 static const BcParseNext bc_parse_next_read =
817 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
821 static const BcLexType dc_lex_regs[] = {
822 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
823 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
824 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
828 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
830 static const BcLexType dc_lex_tokens[] = {
831 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
832 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
833 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
834 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
835 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
836 BC_LEX_INVALID, BC_LEX_INVALID,
837 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
838 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
839 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
840 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
841 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
842 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
843 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
844 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
845 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
846 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
847 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
848 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
849 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
850 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
851 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
852 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
853 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
854 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
858 static const BcInst dc_parse_insts[] = {
859 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
860 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
861 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
862 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
863 BC_INST_INVALID, BC_INST_INVALID,
864 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
865 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
866 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
867 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
868 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
869 BC_INST_INVALID, BC_INST_INVALID,
870 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
871 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
872 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
873 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
874 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
875 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
876 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
877 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
878 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
879 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
880 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
881 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
885 static const BcNumBinaryOp bc_program_ops[] = {
886 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
889 static const char bc_program_stdin_name[] = "<stdin>";
892 static const char *bc_lib_name = "gen/lib.bc";
894 static const char bc_lib[] = {
895 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
896 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
897 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
898 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
899 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
900 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
901 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
902 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
903 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
904 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
905 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
906 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
907 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
908 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
909 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
910 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
911 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
912 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
913 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
914 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
915 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
916 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
917 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
918 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
919 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
920 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
921 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
922 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
923 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
924 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
925 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
926 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
927 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
928 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
929 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
930 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
931 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
932 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
933 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
934 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
935 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
936 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
937 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
938 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
939 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
940 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
941 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
942 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
943 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
944 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
945 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
946 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
947 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
948 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
949 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
950 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
951 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
952 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
953 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
954 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
955 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
956 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
957 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
958 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
959 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
960 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
961 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
962 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
963 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
964 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
965 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
966 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
967 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
968 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
969 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
970 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
971 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
972 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
973 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
974 117,114,110,40,97,42,114,47,49,41,10,125,10,0
978 static void fflush_and_check(void)
981 if (ferror(stdout) || ferror(stderr))
982 bb_perror_msg_and_die("output error");
985 static void quit(void) NORETURN;
986 static void quit(void)
989 bb_perror_msg_and_die("input error");
994 static int bc_error(const char *fmt, ...)
999 bb_verror_msg(fmt, p, NULL);
1003 return BC_STATUS_FAILURE;
1006 static int bc_posix_error(const char *fmt, ...)
1010 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
1011 return BC_STATUS_SUCCESS;
1014 bb_verror_msg(fmt, p, NULL);
1017 // Do we treat non-POSIX constructs as errors?
1018 if (!(option_mask32 & BC_FLAG_S))
1019 return BC_STATUS_SUCCESS; // no, it's a warning
1022 return BC_STATUS_FAILURE;
1025 static void bc_vec_grow(BcVec *v, size_t n)
1027 size_t cap = v->cap * 2;
1028 while (cap < v->len + n) cap *= 2;
1029 v->v = xrealloc(v->v, v->size * cap);
1033 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1036 v->cap = BC_VEC_START_CAP;
1039 v->v = xmalloc(esize * BC_VEC_START_CAP);
1042 static void bc_char_vec_init(BcVec *v)
1044 bc_vec_init(v, sizeof(char), NULL);
1047 static void bc_vec_expand(BcVec *v, size_t req)
1050 v->v = xrealloc(v->v, v->size * req);
1055 static void bc_vec_npop(BcVec *v, size_t n)
1060 size_t len = v->len - n;
1061 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1065 static void bc_vec_pop_all(BcVec *v)
1067 bc_vec_npop(v, v->len);
1070 static void bc_vec_push(BcVec *v, const void *data)
1072 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1073 memmove(v->v + (v->size * v->len), data, v->size);
1077 static void bc_vec_pushByte(BcVec *v, char data)
1079 bc_vec_push(v, &data);
1082 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1085 bc_vec_push(v, data);
1090 if (v->len == v->cap) bc_vec_grow(v, 1);
1092 ptr = v->v + v->size * idx;
1094 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1095 memmove(ptr, data, v->size);
1099 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1102 bc_vec_expand(v, len + 1);
1103 memcpy(v->v, str, len);
1106 bc_vec_pushByte(v, '\0');
1109 static void bc_vec_concat(BcVec *v, const char *str)
1113 if (v->len == 0) bc_vec_pushByte(v, '\0');
1115 len = v->len + strlen(str);
1117 if (v->cap < len) bc_vec_grow(v, len - v->len);
1123 static void *bc_vec_item(const BcVec *v, size_t idx)
1125 return v->v + v->size * idx;
1128 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1130 return v->v + v->size * (v->len - idx - 1);
1133 static void bc_vec_free(void *vec)
1135 BcVec *v = (BcVec *) vec;
1140 static size_t bc_map_find(const BcVec *v, const void *ptr)
1142 size_t low = 0, high = v->len;
1144 while (low < high) {
1146 size_t mid = (low + high) / 2;
1147 BcId *id = bc_vec_item(v, mid);
1148 int result = bc_id_cmp(ptr, id);
1152 else if (result < 0)
1161 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1163 size_t n = *i = bc_map_find(v, ptr);
1166 bc_vec_push(v, ptr);
1167 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1168 return 0; // "was not inserted"
1170 bc_vec_pushAt(v, ptr, n);
1171 return 1; // "was inserted"
1174 static size_t bc_map_index(const BcVec *v, const void *ptr)
1176 size_t i = bc_map_find(v, ptr);
1177 if (i >= v->len) return BC_VEC_INVALID_IDX;
1178 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1181 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1190 bc_vec_pop_all(vec);
1193 #if ENABLE_FEATURE_BC_SIGNALS
1194 if (bb_got_signal) { // ^C was pressed
1196 bb_got_signal = 0; // resets G_interrupt to zero
1198 ? "\ninterrupt (type \"quit\" to exit)\n"
1199 : "\ninterrupt (type \"q\" to exit)\n"
1203 if (G.ttyin && !G_posix)
1204 fputs(prompt, stderr);
1206 #if ENABLE_FEATURE_BC_SIGNALS
1212 #if ENABLE_FEATURE_BC_SIGNALS
1213 // Both conditions appear simultaneously, check both just in case
1214 if (errno == EINTR || bb_got_signal) {
1221 quit(); // this emits error message
1223 // Note: EOF does not append '\n', therefore:
1224 // printf 'print 123\n' | bc - works
1225 // printf 'print 123' | bc - fails (syntax error)
1229 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1232 // Bad chars on this line, ignore entire line
1233 bc_error("illegal character 0x%02x", i);
1237 bc_vec_push(vec, &c);
1238 } while (i != '\n');
1239 } while (bad_chars);
1241 bc_vec_pushByte(vec, '\0');
1243 return BC_STATUS_SUCCESS;
1246 static char* bc_read_file(const char *path)
1249 size_t size = ((size_t) -1);
1252 buf = xmalloc_open_read_close(path, &size);
1254 for (i = 0; i < size; ++i) {
1256 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1268 static void bc_args(int argc, char **argv)
1274 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1275 opts = getopt32long(argv, "xwvsqli",
1276 "extended-register\0" No_argument "x"
1277 "warn\0" No_argument "w"
1278 "version\0" No_argument "v"
1279 "standard\0" No_argument "s"
1280 "quiet\0" No_argument "q"
1281 "mathlib\0" No_argument "l"
1282 "interactive\0" No_argument "i"
1285 opts = getopt32(argv, "xwvsqli");
1287 if (getenv("POSIXLY_CORRECT"))
1288 option_mask32 |= BC_FLAG_S;
1290 if (opts & BC_FLAG_V) bc_vm_info();
1291 // should not be necessary, getopt32() handles this??
1292 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1294 for (i = optind; i < argc; ++i)
1295 bc_vec_push(&G.files, argv + i);
1298 static void bc_num_setToZero(BcNum *n, size_t scale)
1305 static void bc_num_zero(BcNum *n)
1307 bc_num_setToZero(n, 0);
1310 static void bc_num_one(BcNum *n)
1312 bc_num_setToZero(n, 0);
1317 static void bc_num_ten(BcNum *n)
1319 bc_num_setToZero(n, 0);
1325 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1329 for (i = 0; i < len; ++i) {
1330 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1337 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1341 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1342 return BC_NUM_NEG(i + 1, c < 0);
1345 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1347 size_t i, min, a_int, b_int, diff;
1348 BcDig *max_num, *min_num;
1349 bool a_max, neg = false;
1352 if (a == b) return 0;
1353 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1354 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1364 a_int = BC_NUM_INT(a);
1365 b_int = BC_NUM_INT(b);
1367 a_max = (a->rdx > b->rdx);
1369 if (a_int != 0) return (ssize_t) a_int;
1373 diff = a->rdx - b->rdx;
1374 max_num = a->num + diff;
1379 diff = b->rdx - a->rdx;
1380 max_num = b->num + diff;
1384 cmp = bc_num_compare(max_num, min_num, b_int + min);
1385 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1387 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1388 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1394 static void bc_num_truncate(BcNum *n, size_t places)
1396 if (places == 0) return;
1402 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1406 static void bc_num_extend(BcNum *n, size_t places)
1408 size_t len = n->len + places;
1412 if (n->cap < len) bc_num_expand(n, len);
1414 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1415 memset(n->num, 0, sizeof(BcDig) * places);
1422 static void bc_num_clean(BcNum *n)
1424 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1427 else if (n->len < n->rdx)
1431 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1434 bc_num_extend(n, scale - n->rdx);
1436 bc_num_truncate(n, n->rdx - scale);
1439 if (n->len != 0) n->neg = !neg1 != !neg2;
1442 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1447 b->len = n->len - idx;
1449 a->rdx = b->rdx = 0;
1451 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1452 memcpy(a->num, n->num, idx * sizeof(BcDig));
1463 static BcStatus bc_num_shift(BcNum *n, size_t places)
1465 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1466 if (places + n->len > BC_MAX_NUM)
1467 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1469 if (n->rdx >= places)
1472 bc_num_extend(n, places - n->rdx);
1478 return BC_STATUS_SUCCESS;
1481 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1490 return bc_num_div(&one, a, b, scale);
1493 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1495 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1496 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1499 // Because this function doesn't need to use scale (per the bc spec),
1500 // I am hijacking it to say whether it's doing an add or a subtract.
1504 if (sub && c->len) c->neg = !c->neg;
1505 return BC_STATUS_SUCCESS;
1507 else if (b->len == 0) {
1509 return BC_STATUS_SUCCESS;
1513 c->rdx = BC_MAX(a->rdx, b->rdx);
1514 min_rdx = BC_MIN(a->rdx, b->rdx);
1517 if (a->rdx > b->rdx) {
1518 diff = a->rdx - b->rdx;
1520 ptr_a = a->num + diff;
1524 diff = b->rdx - a->rdx;
1527 ptr_b = b->num + diff;
1530 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1533 a_int = BC_NUM_INT(a);
1534 b_int = BC_NUM_INT(b);
1536 if (a_int > b_int) {
1547 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1548 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1550 ptr_c[i] = (BcDig)(in % 10);
1553 for (; i < max + min_rdx; ++i, ++c->len) {
1554 in = ((int) ptr[i]) + carry;
1556 ptr_c[i] = (BcDig)(in % 10);
1559 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1561 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1564 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1567 BcNum *minuend, *subtrahend;
1569 bool aneg, bneg, neg;
1571 // Because this function doesn't need to use scale (per the bc spec),
1572 // I am hijacking it to say whether it's doing an add or a subtract.
1576 if (sub && c->len) c->neg = !c->neg;
1577 return BC_STATUS_SUCCESS;
1579 else if (b->len == 0) {
1581 return BC_STATUS_SUCCESS;
1586 a->neg = b->neg = false;
1588 cmp = bc_num_cmp(a, b);
1594 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1595 return BC_STATUS_SUCCESS;
1604 if (sub) neg = !neg;
1609 bc_num_copy(c, minuend);
1612 if (c->rdx < subtrahend->rdx) {
1613 bc_num_extend(c, subtrahend->rdx - c->rdx);
1617 start = c->rdx - subtrahend->rdx;
1619 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1623 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1626 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1631 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1632 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1633 bool aone = BC_NUM_ONE(a);
1635 if (a->len == 0 || b->len == 0) {
1637 return BC_STATUS_SUCCESS;
1639 else if (aone || BC_NUM_ONE(b)) {
1640 bc_num_copy(c, aone ? b : a);
1641 return BC_STATUS_SUCCESS;
1644 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1645 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1647 bc_num_expand(c, a->len + b->len + 1);
1649 memset(c->num, 0, sizeof(BcDig) * c->cap);
1650 c->len = carry = len = 0;
1652 for (i = 0; i < b->len; ++i) {
1654 for (j = 0; j < a->len; ++j) {
1655 int in = (int) c->num[i + j];
1656 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1658 c->num[i + j] = (BcDig)(in % 10);
1661 c->num[i + j] += (BcDig) carry;
1662 len = BC_MAX(len, i + j + !!carry);
1668 return BC_STATUS_SUCCESS;
1671 bc_num_init(&l1, max);
1672 bc_num_init(&h1, max);
1673 bc_num_init(&l2, max);
1674 bc_num_init(&h2, max);
1675 bc_num_init(&m1, max);
1676 bc_num_init(&m2, max);
1677 bc_num_init(&z0, max);
1678 bc_num_init(&z1, max);
1679 bc_num_init(&z2, max);
1680 bc_num_init(&temp, max + max);
1682 bc_num_split(a, max2, &l1, &h1);
1683 bc_num_split(b, max2, &l2, &h2);
1685 s = bc_num_add(&h1, &l1, &m1, 0);
1687 s = bc_num_add(&h2, &l2, &m2, 0);
1690 s = bc_num_k(&h1, &h2, &z0);
1692 s = bc_num_k(&m1, &m2, &z1);
1694 s = bc_num_k(&l1, &l2, &z2);
1697 s = bc_num_sub(&z1, &z0, &temp, 0);
1699 s = bc_num_sub(&temp, &z2, &z1, 0);
1702 s = bc_num_shift(&z0, max2 * 2);
1704 s = bc_num_shift(&z1, max2);
1706 s = bc_num_add(&z0, &z1, &temp, 0);
1708 s = bc_num_add(&temp, &z2, c, 0);
1724 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1728 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1730 scale = BC_MAX(scale, a->rdx);
1731 scale = BC_MAX(scale, b->rdx);
1732 scale = BC_MIN(a->rdx + b->rdx, scale);
1733 maxrdx = BC_MAX(maxrdx, scale);
1735 bc_num_init(&cpa, a->len);
1736 bc_num_init(&cpb, b->len);
1738 bc_num_copy(&cpa, a);
1739 bc_num_copy(&cpb, b);
1740 cpa.neg = cpb.neg = false;
1742 s = bc_num_shift(&cpa, maxrdx);
1744 s = bc_num_shift(&cpb, maxrdx);
1746 s = bc_num_k(&cpa, &cpb, c);
1750 bc_num_expand(c, c->len + maxrdx);
1752 if (c->len < maxrdx) {
1753 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1758 bc_num_retireMul(c, scale, a->neg, b->neg);
1766 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1768 BcStatus s = BC_STATUS_SUCCESS;
1775 return bc_error("divide by zero");
1776 else if (a->len == 0) {
1777 bc_num_setToZero(c, scale);
1778 return BC_STATUS_SUCCESS;
1780 else if (BC_NUM_ONE(b)) {
1782 bc_num_retireMul(c, scale, a->neg, b->neg);
1783 return BC_STATUS_SUCCESS;
1786 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1787 bc_num_copy(&cp, a);
1791 bc_num_expand(&cp, len + 2);
1792 bc_num_extend(&cp, len - cp.len);
1795 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1797 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1799 if (b->rdx == b->len) {
1800 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1804 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1806 // We want an extra zero in front to make things simpler.
1807 cp.num[cp.len++] = 0;
1810 bc_num_expand(c, cp.len);
1813 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1818 for (i = end - 1; !s && i < end; --i) {
1820 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1821 bc_num_subArrays(n, p, len);
1825 bc_num_retireMul(c, scale, a->neg, b->neg);
1828 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1831 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1832 BcNum *restrict d, size_t scale, size_t ts)
1839 return bc_error("divide by zero");
1842 bc_num_setToZero(d, ts);
1843 return BC_STATUS_SUCCESS;
1846 bc_num_init(&temp, d->cap);
1847 bc_num_d(a, b, c, scale);
1849 if (scale != 0) scale = ts;
1851 s = bc_num_m(c, b, &temp, scale);
1853 s = bc_num_sub(a, &temp, d, scale);
1856 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1859 bc_num_retireMul(d, ts, a->neg, b->neg);
1867 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1871 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1873 bc_num_init(&c1, len);
1874 s = bc_num_r(a, b, &c1, c, scale, ts);
1880 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1882 BcStatus s = BC_STATUS_SUCCESS;
1885 size_t i, powrdx, resrdx;
1888 if (b->rdx) return bc_error("non integer number");
1892 return BC_STATUS_SUCCESS;
1894 else if (a->len == 0) {
1895 bc_num_setToZero(c, scale);
1896 return BC_STATUS_SUCCESS;
1898 else if (BC_NUM_ONE(b)) {
1902 s = bc_num_inv(a, c, scale);
1909 s = bc_num_ulong(b, &pow);
1912 bc_num_init(©, a->len);
1913 bc_num_copy(©, a);
1915 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1919 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
1921 s = bc_num_mul(©, ©, ©, powrdx);
1925 bc_num_copy(c, ©);
1927 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
1930 s = bc_num_mul(©, ©, ©, powrdx);
1935 s = bc_num_mul(c, ©, c, resrdx);
1941 s = bc_num_inv(c, c, scale);
1945 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1947 // We can't use bc_num_clean() here.
1948 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1949 if (zero) bc_num_setToZero(c, scale);
1956 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1957 BcNumBinaryOp op, size_t req)
1960 BcNum num2, *ptr_a, *ptr_b;
1965 memcpy(ptr_a, c, sizeof(BcNum));
1974 memcpy(ptr_b, c, sizeof(BcNum));
1982 bc_num_init(c, req);
1984 bc_num_expand(c, req);
1986 s = op(ptr_a, ptr_b, c, scale);
1988 if (init) bc_num_free(&num2);
1993 static bool bc_num_strValid(const char *val, size_t base)
1996 bool small, radix = false;
1997 size_t i, len = strlen(val);
1999 if (!len) return true;
2002 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2004 for (i = 0; i < len; ++i) {
2010 if (radix) return false;
2016 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2023 static void bc_num_parseDecimal(BcNum *n, const char *val)
2029 for (i = 0; val[i] == '0'; ++i);
2036 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2037 bc_num_expand(n, len);
2040 ptr = strchr(val, '.');
2044 n->rdx = (size_t)((val + len) - (ptr + 1));
2047 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2048 n->num[n->len] = val[i] - '0';
2052 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2055 BcNum temp, mult, result;
2059 size_t i, digits, len = strlen(val);
2063 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2066 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2067 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2069 for (i = 0; i < len; ++i) {
2072 if (c == '.') break;
2074 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2076 s = bc_num_mul(n, base, &mult, 0);
2077 if (s) goto int_err;
2078 bc_num_ulong2num(&temp, v);
2079 s = bc_num_add(&mult, &temp, n, 0);
2080 if (s) goto int_err;
2085 if (c == 0) goto int_err;
2088 bc_num_init(&result, base->len);
2089 bc_num_zero(&result);
2092 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2097 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2099 s = bc_num_mul(&result, base, &result, 0);
2101 bc_num_ulong2num(&temp, v);
2102 s = bc_num_add(&result, &temp, &result, 0);
2104 s = bc_num_mul(&mult, base, &mult, 0);
2108 s = bc_num_div(&result, &mult, &result, digits);
2110 s = bc_num_add(n, &result, n, digits);
2114 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2120 bc_num_free(&result);
2126 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2128 if (*nchars == line_len - 1) {
2136 static void bc_num_printChar(size_t num, size_t width, bool radix,
2137 size_t *nchars, size_t line_len)
2139 (void) radix, (void) line_len;
2140 bb_putchar((char) num);
2141 *nchars = *nchars + width;
2145 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2146 size_t *nchars, size_t line_len)
2150 bc_num_printNewline(nchars, line_len);
2151 bb_putchar(radix ? '.' : ' ');
2154 bc_num_printNewline(nchars, line_len);
2155 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2158 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2160 bc_num_printNewline(nchars, line_len);
2163 bb_putchar(((char) dig) + '0');
2167 static void bc_num_printHex(size_t num, size_t width, bool radix,
2168 size_t *nchars, size_t line_len)
2171 bc_num_printNewline(nchars, line_len);
2176 bc_num_printNewline(nchars, line_len);
2177 bb_putchar(bb_hexdigits_upcase[num]);
2178 *nchars = *nchars + width;
2181 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2183 size_t i, rdx = n->rdx - 1;
2185 if (n->neg) bb_putchar('-');
2186 (*nchars) += n->neg;
2188 for (i = n->len - 1; i < n->len; --i)
2189 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2192 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2193 size_t *nchars, size_t len, BcNumDigitOp print)
2197 BcNum intp, fracp, digit, frac_len;
2198 unsigned long dig, *ptr;
2203 print(0, width, false, nchars, len);
2204 return BC_STATUS_SUCCESS;
2207 bc_vec_init(&stack, sizeof(long), NULL);
2208 bc_num_init(&intp, n->len);
2209 bc_num_init(&fracp, n->rdx);
2210 bc_num_init(&digit, width);
2211 bc_num_init(&frac_len, BC_NUM_INT(n));
2212 bc_num_copy(&intp, n);
2213 bc_num_one(&frac_len);
2215 bc_num_truncate(&intp, intp.rdx);
2216 s = bc_num_sub(n, &intp, &fracp, 0);
2219 while (intp.len != 0) {
2220 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2222 s = bc_num_ulong(&digit, &dig);
2224 bc_vec_push(&stack, &dig);
2227 for (i = 0; i < stack.len; ++i) {
2228 ptr = bc_vec_item_rev(&stack, i);
2229 print(*ptr, width, false, nchars, len);
2232 if (!n->rdx) goto err;
2234 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2235 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2237 s = bc_num_ulong(&fracp, &dig);
2239 bc_num_ulong2num(&intp, dig);
2240 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2242 print(dig, width, radix, nchars, len);
2243 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2248 bc_num_free(&frac_len);
2249 bc_num_free(&digit);
2250 bc_num_free(&fracp);
2252 bc_vec_free(&stack);
2256 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2257 size_t *nchars, size_t line_len)
2264 if (neg) bb_putchar('-');
2269 if (base_t <= BC_NUM_MAX_IBASE) {
2271 print = bc_num_printHex;
2274 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2275 print = bc_num_printDigits;
2278 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2285 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2287 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2291 static void bc_num_init(BcNum *n, size_t req)
2293 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2294 memset(n, 0, sizeof(BcNum));
2295 n->num = xmalloc(req);
2299 static void bc_num_expand(BcNum *n, size_t req)
2301 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2303 n->num = xrealloc(n->num, req);
2308 static void bc_num_free(void *num)
2310 free(((BcNum *) num)->num);
2313 static void bc_num_copy(BcNum *d, BcNum *s)
2316 bc_num_expand(d, s->cap);
2320 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2324 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2327 if (!bc_num_strValid(val, base_t))
2328 return bc_error("bad number string");
2331 bc_num_parseDecimal(n, val);
2333 bc_num_parseBase(n, val, base);
2335 return BC_STATUS_SUCCESS;
2338 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2339 size_t *nchars, size_t line_len)
2341 BcStatus s = BC_STATUS_SUCCESS;
2343 bc_num_printNewline(nchars, line_len);
2349 else if (base_t == 10)
2350 bc_num_printDecimal(n, nchars, line_len);
2352 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2362 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2367 if (n->neg) return bc_error("negative number");
2369 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2371 unsigned long prev = *result, powprev = pow;
2373 *result += ((unsigned long) n->num[i]) * pow;
2376 if (*result < prev || pow < powprev)
2377 return bc_error("overflow");
2380 return BC_STATUS_SUCCESS;
2383 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2391 if (val == 0) return;
2393 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2394 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2397 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2399 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2401 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2404 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2406 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2408 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2411 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2413 size_t req = BC_NUM_MREQ(a, b, scale);
2414 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2417 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2419 size_t req = BC_NUM_MREQ(a, b, scale);
2420 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2423 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2425 size_t req = BC_NUM_MREQ(a, b, scale);
2426 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2429 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2431 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2434 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2437 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2438 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2439 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2441 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2442 bc_num_expand(b, req);
2445 bc_num_setToZero(b, scale);
2446 return BC_STATUS_SUCCESS;
2449 return bc_error("negative number");
2450 else if (BC_NUM_ONE(a)) {
2452 bc_num_extend(b, scale);
2453 return BC_STATUS_SUCCESS;
2456 scale = BC_MAX(scale, a->rdx) + 1;
2457 len = a->len + scale;
2459 bc_num_init(&num1, len);
2460 bc_num_init(&num2, len);
2461 bc_num_init(&half, BC_NUM_DEF_SIZE);
2467 bc_num_init(&f, len);
2468 bc_num_init(&fprime, len);
2474 pow = BC_NUM_INT(a);
2483 pow -= 2 - (pow & 1);
2485 bc_num_extend(x0, pow);
2487 // Make sure to move the radix back.
2491 x0->rdx = digs = digs1 = 0;
2493 len = BC_NUM_INT(x0) + resrdx - 1;
2495 while (cmp != 0 || digs < len) {
2497 s = bc_num_div(a, x0, &f, resrdx);
2499 s = bc_num_add(x0, &f, &fprime, resrdx);
2501 s = bc_num_mul(&fprime, &half, x1, resrdx);
2504 cmp = bc_num_cmp(x1, x0);
2505 digs = x1->len - (unsigned long long) llabs(cmp);
2507 if (cmp == cmp2 && digs == digs1)
2512 resrdx += times > 4;
2525 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2528 bc_num_free(&fprime);
2536 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2542 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2545 memcpy(&num2, c, sizeof(BcNum));
2547 bc_num_init(c, len);
2552 bc_num_expand(c, len);
2555 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2557 if (init) bc_num_free(&num2);
2563 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2566 BcNum base, exp, two, temp;
2569 return bc_error("divide by zero");
2570 if (a->rdx || b->rdx || c->rdx)
2571 return bc_error("non integer number");
2573 return bc_error("negative number");
2575 bc_num_expand(d, c->len);
2576 bc_num_init(&base, c->len);
2577 bc_num_init(&exp, b->len);
2578 bc_num_init(&two, BC_NUM_DEF_SIZE);
2579 bc_num_init(&temp, b->len);
2585 s = bc_num_rem(a, c, &base, 0);
2587 bc_num_copy(&exp, b);
2589 while (exp.len != 0) {
2591 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2594 if (BC_NUM_ONE(&temp)) {
2595 s = bc_num_mul(d, &base, &temp, 0);
2597 s = bc_num_rem(&temp, c, d, 0);
2601 s = bc_num_mul(&base, &base, &temp, 0);
2603 s = bc_num_rem(&temp, c, &base, 0);
2616 static int bc_id_cmp(const void *e1, const void *e2)
2618 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2621 static void bc_id_free(void *id)
2623 free(((BcId *) id)->name);
2626 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2631 for (i = 0; i < f->autos.len; ++i) {
2632 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2633 return bc_error("function parameter or auto var has the same name as another");
2639 bc_vec_push(&f->autos, &a);
2641 return BC_STATUS_SUCCESS;
2644 static void bc_func_init(BcFunc *f)
2646 bc_char_vec_init(&f->code);
2647 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2648 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2652 static void bc_func_free(void *func)
2654 BcFunc *f = (BcFunc *) func;
2655 bc_vec_free(&f->code);
2656 bc_vec_free(&f->autos);
2657 bc_vec_free(&f->labels);
2660 static void bc_array_init(BcVec *a, bool nums)
2663 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2665 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2666 bc_array_expand(a, 1);
2669 static void bc_array_copy(BcVec *d, const BcVec *s)
2674 bc_vec_expand(d, s->cap);
2677 for (i = 0; i < s->len; ++i) {
2678 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2679 bc_num_init(dnum, snum->len);
2680 bc_num_copy(dnum, snum);
2684 static void bc_array_expand(BcVec *a, size_t len)
2688 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2689 while (len > a->len) {
2690 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2691 bc_vec_push(a, &data.n);
2695 while (len > a->len) {
2696 bc_array_init(&data.v, true);
2697 bc_vec_push(a, &data.v);
2702 static void bc_string_free(void *string)
2704 free(*((char **) string));
2708 static void bc_result_copy(BcResult *d, BcResult *src)
2714 case BC_RESULT_TEMP:
2715 case BC_RESULT_IBASE:
2716 case BC_RESULT_SCALE:
2717 case BC_RESULT_OBASE:
2719 bc_num_init(&d->d.n, src->d.n.len);
2720 bc_num_copy(&d->d.n, &src->d.n);
2725 case BC_RESULT_ARRAY:
2726 case BC_RESULT_ARRAY_ELEM:
2728 d->d.id.name = xstrdup(src->d.id.name);
2732 case BC_RESULT_CONSTANT:
2733 case BC_RESULT_LAST:
2737 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2744 static void bc_result_free(void *result)
2746 BcResult *r = (BcResult *) result;
2750 case BC_RESULT_TEMP:
2751 case BC_RESULT_IBASE:
2752 case BC_RESULT_SCALE:
2753 case BC_RESULT_OBASE:
2755 bc_num_free(&r->d.n);
2760 case BC_RESULT_ARRAY:
2761 case BC_RESULT_ARRAY_ELEM:
2775 static void bc_lex_lineComment(BcLex *l)
2777 l->t.t = BC_LEX_WHITESPACE;
2778 while (l->i < l->len && l->buf[l->i++] != '\n');
2782 static void bc_lex_whitespace(BcLex *l)
2785 l->t.t = BC_LEX_WHITESPACE;
2786 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2789 static BcStatus bc_lex_number(BcLex *l, char start)
2791 const char *buf = l->buf + l->i;
2792 size_t len, hits = 0, bslashes = 0, i = 0, j;
2794 bool last_pt, pt = start == '.';
2797 l->t.t = BC_LEX_NUMBER;
2799 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2800 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2814 len = i + !last_pt - bslashes * 2;
2815 if (len > BC_MAX_NUM)
2816 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2818 bc_vec_pop_all(&l->t.v);
2819 bc_vec_expand(&l->t.v, len + 1);
2820 bc_vec_push(&l->t.v, &start);
2822 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2826 // If we have hit a backslash, skip it. We don't have
2827 // to check for a newline because it's guaranteed.
2828 if (hits < bslashes && c == '\\') {
2834 bc_vec_push(&l->t.v, &c);
2837 bc_vec_pushByte(&l->t.v, '\0');
2840 return BC_STATUS_SUCCESS;
2843 static BcStatus bc_lex_name(BcLex *l)
2846 const char *buf = l->buf + l->i - 1;
2849 l->t.t = BC_LEX_NAME;
2851 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2853 if (i > BC_MAX_STRING)
2854 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2855 bc_vec_string(&l->t.v, i, buf);
2857 // Increment the index. We minus 1 because it has already been incremented.
2860 return BC_STATUS_SUCCESS;
2863 static void bc_lex_init(BcLex *l, BcLexNext next)
2866 bc_char_vec_init(&l->t.v);
2869 static void bc_lex_free(BcLex *l)
2871 bc_vec_free(&l->t.v);
2874 static void bc_lex_file(BcLex *l, const char *file)
2881 static BcStatus bc_lex_next(BcLex *l)
2886 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
2888 l->line += l->newline;
2889 l->t.t = BC_LEX_EOF;
2891 l->newline = (l->i == l->len);
2892 if (l->newline) return BC_STATUS_SUCCESS;
2894 // Loop until failure or we don't have whitespace. This
2895 // is so the parser doesn't get inundated with whitespace.
2898 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2903 static BcStatus bc_lex_text(BcLex *l, const char *text)
2907 l->len = strlen(text);
2908 l->t.t = l->t.last = BC_LEX_INVALID;
2909 return bc_lex_next(l);
2913 static BcStatus bc_lex_identifier(BcLex *l)
2917 const char *buf = l->buf + l->i - 1;
2919 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2921 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2923 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2925 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2927 if (!bc_lex_kws[i].posix) {
2928 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
2932 // We minus 1 because the index has already been incremented.
2934 return BC_STATUS_SUCCESS;
2941 if (l->t.v.len - 1 > 1)
2942 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
2947 static BcStatus bc_lex_string(BcLex *l)
2949 size_t len, nls = 0, i = l->i;
2952 l->t.t = BC_LEX_STR;
2954 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2958 return bc_error("string end could not be found");
2962 if (len > BC_MAX_STRING)
2963 return bc_error("string too long: must be [1, BC_STRING_MAX]");
2964 bc_vec_string(&l->t.v, len, l->buf + l->i);
2969 return BC_STATUS_SUCCESS;
2972 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2974 if (l->buf[l->i] == '=') {
2982 static BcStatus bc_lex_comment(BcLex *l)
2985 const char *buf = l->buf;
2987 l->t.t = BC_LEX_WHITESPACE;
3000 return bc_error("comment end could not be found");
3009 return BC_STATUS_SUCCESS;
3012 static BcStatus bc_lex_token(BcLex *l)
3014 BcStatus s = BC_STATUS_SUCCESS;
3015 char c = l->buf[l->i++], c2;
3017 // This is the workhorse of the lexer.
3024 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3034 bc_lex_whitespace(l);
3040 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3042 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3043 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3052 s = bc_lex_string(l);
3058 s = bc_posix_error("POSIX does not allow '#' script comments");
3061 bc_lex_lineComment(l);
3068 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3077 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3081 l->t.t = BC_LEX_OP_BOOL_AND;
3084 l->t.t = BC_LEX_INVALID;
3085 s = bc_error("bad character '%c'", '&');
3094 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3100 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3109 l->t.t = BC_LEX_OP_INC;
3112 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3118 l->t.t = BC_LEX_COMMA;
3127 l->t.t = BC_LEX_OP_DEC;
3130 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3136 if (isdigit(l->buf[l->i]))
3137 s = bc_lex_number(l, c);
3139 l->t.t = BC_LEX_KEY_LAST;
3140 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3149 s = bc_lex_comment(l);
3151 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3172 s = bc_lex_number(l, c);
3178 l->t.t = BC_LEX_SCOLON;
3184 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3190 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3196 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3203 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3209 if (l->buf[l->i] == '\n') {
3210 l->t.t = BC_LEX_WHITESPACE;
3214 s = bc_error("bad character '%c'", c);
3220 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3251 s = bc_lex_identifier(l);
3258 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3267 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3271 l->t.t = BC_LEX_OP_BOOL_OR;
3274 l->t.t = BC_LEX_INVALID;
3275 s = bc_error("bad character '%c'", c);
3283 l->t.t = BC_LEX_INVALID;
3284 s = bc_error("bad character '%c'", c);
3294 static BcStatus dc_lex_register(BcLex *l)
3296 BcStatus s = BC_STATUS_SUCCESS;
3298 if (isspace(l->buf[l->i - 1])) {
3299 bc_lex_whitespace(l);
3302 s = bc_error("extended register");
3307 bc_vec_pop_all(&l->t.v);
3308 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3309 bc_vec_pushByte(&l->t.v, '\0');
3310 l->t.t = BC_LEX_NAME;
3316 static BcStatus dc_lex_string(BcLex *l)
3318 size_t depth = 1, nls = 0, i = l->i;
3321 l->t.t = BC_LEX_STR;
3322 bc_vec_pop_all(&l->t.v);
3324 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3326 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3327 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3330 if (depth) bc_vec_push(&l->t.v, &c);
3335 return bc_error("string end could not be found");
3338 bc_vec_pushByte(&l->t.v, '\0');
3339 if (i - l->i > BC_MAX_STRING)
3340 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3345 return BC_STATUS_SUCCESS;
3348 static BcStatus dc_lex_token(BcLex *l)
3350 BcStatus s = BC_STATUS_SUCCESS;
3351 char c = l->buf[l->i++], c2;
3354 for (i = 0; i < dc_lex_regs_len; ++i) {
3355 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3358 if (c >= '%' && c <= '~' &&
3359 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3364 // This is the workhorse of the lexer.
3369 l->t.t = BC_LEX_EOF;
3380 l->newline = (c == '\n');
3381 bc_lex_whitespace(l);
3390 l->t.t = BC_LEX_OP_REL_NE;
3392 l->t.t = BC_LEX_OP_REL_LE;
3394 l->t.t = BC_LEX_OP_REL_GE;
3396 return bc_error("bad character '%c'", c);
3404 bc_lex_lineComment(l);
3410 if (isdigit(l->buf[l->i]))
3411 s = bc_lex_number(l, c);
3413 s = bc_error("bad character '%c'", c);
3434 s = bc_lex_number(l, c);
3440 s = dc_lex_string(l);
3446 l->t.t = BC_LEX_INVALID;
3447 s = bc_error("bad character '%c'", c);
3456 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3458 bc_program_addFunc(name, idx);
3459 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3462 static void bc_parse_pushName(BcParse *p, char *name)
3464 size_t i = 0, len = strlen(name);
3466 for (; i < len; ++i) bc_parse_push(p, name[i]);
3467 bc_parse_push(p, BC_PARSE_STREND);
3472 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3474 unsigned char amt, i, nums[sizeof(size_t)];
3476 for (amt = 0; idx; ++amt) {
3477 nums[amt] = (char) idx;
3478 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3481 bc_parse_push(p, amt);
3482 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3485 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3487 char *num = xstrdup(p->l.t.v.v);
3488 size_t idx = G.prog.consts.len;
3490 bc_vec_push(&G.prog.consts, &num);
3492 bc_parse_push(p, BC_INST_NUM);
3493 bc_parse_pushIndex(p, idx);
3496 (*prev) = BC_INST_NUM;
3499 static BcStatus bc_parse_text(BcParse *p, const char *text)
3503 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3505 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3506 p->l.t.t = BC_LEX_INVALID;
3509 if (!BC_PARSE_CAN_EXEC(p))
3510 return bc_error("file is not executable");
3513 return bc_lex_text(&p->l, text);
3516 // Called when bc/dc_parse_parse() detects a failure,
3517 // resets parsing structures.
3518 static void bc_parse_reset(BcParse *p)
3520 if (p->fidx != BC_PROG_MAIN) {
3521 p->func->nparams = 0;
3522 bc_vec_pop_all(&p->func->code);
3523 bc_vec_pop_all(&p->func->autos);
3524 bc_vec_pop_all(&p->func->labels);
3526 bc_parse_updateFunc(p, BC_PROG_MAIN);
3530 p->l.t.t = BC_LEX_EOF;
3531 p->auto_part = (p->nbraces = 0);
3533 bc_vec_npop(&p->flags, p->flags.len - 1);
3534 bc_vec_pop_all(&p->exits);
3535 bc_vec_pop_all(&p->conds);
3536 bc_vec_pop_all(&p->ops);
3541 static void bc_parse_free(BcParse *p)
3543 bc_vec_free(&p->flags);
3544 bc_vec_free(&p->exits);
3545 bc_vec_free(&p->conds);
3546 bc_vec_free(&p->ops);
3550 static void bc_parse_create(BcParse *p, size_t func,
3551 BcParseParse parse, BcLexNext next)
3553 memset(p, 0, sizeof(BcParse));
3555 bc_lex_init(&p->l, next);
3556 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3557 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3558 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3559 bc_vec_pushByte(&p->flags, 0);
3560 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3563 // p->auto_part = p->nbraces = 0; - already is
3564 bc_parse_updateFunc(p, func);
3568 static BcStatus bc_parse_else(BcParse *p);
3569 static BcStatus bc_parse_stmt(BcParse *p);
3571 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3572 size_t *nexprs, bool next)
3574 BcStatus s = BC_STATUS_SUCCESS;
3576 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3577 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3579 while (p->ops.len > start) {
3581 t = BC_PARSE_TOP_OP(p);
3582 if (t == BC_LEX_LPAREN) break;
3584 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3585 if (l >= r && (l != r || !left)) break;
3587 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3588 bc_vec_pop(&p->ops);
3589 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3592 bc_vec_push(&p->ops, &type);
3593 if (next) s = bc_lex_next(&p->l);
3598 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3602 if (p->ops.len <= ops_bgn)
3603 return bc_error("bad expression");
3604 top = BC_PARSE_TOP_OP(p);
3606 while (top != BC_LEX_LPAREN) {
3608 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3610 bc_vec_pop(&p->ops);
3611 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3613 if (p->ops.len <= ops_bgn)
3614 return bc_error("bad expression");
3615 top = BC_PARSE_TOP_OP(p);
3618 bc_vec_pop(&p->ops);
3620 return bc_lex_next(&p->l);
3623 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3629 s = bc_lex_next(&p->l);
3632 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3634 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3635 s = bc_parse_expr(p, flags, bc_parse_next_param);
3638 comma = p->l.t.t == BC_LEX_COMMA;
3640 s = bc_lex_next(&p->l);
3645 if (comma) return bc_error("bad token");
3646 bc_parse_push(p, BC_INST_CALL);
3647 bc_parse_pushIndex(p, nparams);
3649 return BC_STATUS_SUCCESS;
3652 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3655 BcId entry, *entry_ptr;
3660 s = bc_parse_params(p, flags);
3663 if (p->l.t.t != BC_LEX_RPAREN) {
3664 s = bc_error("bad token");
3668 idx = bc_map_index(&G.prog.fn_map, &entry);
3670 if (idx == BC_VEC_INVALID_IDX) {
3671 name = xstrdup(entry.name);
3672 bc_parse_addFunc(p, name, &idx);
3673 idx = bc_map_index(&G.prog.fn_map, &entry);
3679 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3680 bc_parse_pushIndex(p, entry_ptr->idx);
3682 return bc_lex_next(&p->l);
3689 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3694 name = xstrdup(p->l.t.v.v);
3695 s = bc_lex_next(&p->l);
3698 if (p->l.t.t == BC_LEX_LBRACKET) {
3700 s = bc_lex_next(&p->l);
3703 if (p->l.t.t == BC_LEX_RBRACKET) {
3705 if (!(flags & BC_PARSE_ARRAY)) {
3706 s = bc_error("bad expression");
3710 *type = BC_INST_ARRAY;
3714 *type = BC_INST_ARRAY_ELEM;
3716 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3717 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3721 s = bc_lex_next(&p->l);
3723 bc_parse_push(p, *type);
3724 bc_parse_pushName(p, name);
3726 else if (p->l.t.t == BC_LEX_LPAREN) {
3728 if (flags & BC_PARSE_NOCALL) {
3729 s = bc_error("bad token");
3733 *type = BC_INST_CALL;
3734 s = bc_parse_call(p, name, flags);
3737 *type = BC_INST_VAR;
3738 bc_parse_push(p, BC_INST_VAR);
3739 bc_parse_pushName(p, name);
3749 static BcStatus bc_parse_read(BcParse *p)
3753 s = bc_lex_next(&p->l);
3755 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3757 s = bc_lex_next(&p->l);
3759 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3761 bc_parse_push(p, BC_INST_READ);
3763 return bc_lex_next(&p->l);
3766 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3771 s = bc_lex_next(&p->l);
3773 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3775 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3777 s = bc_lex_next(&p->l);
3780 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3783 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3785 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3786 bc_parse_push(p, *prev);
3788 return bc_lex_next(&p->l);
3791 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3795 s = bc_lex_next(&p->l);
3798 if (p->l.t.t != BC_LEX_LPAREN) {
3799 *type = BC_INST_SCALE;
3800 bc_parse_push(p, BC_INST_SCALE);
3801 return BC_STATUS_SUCCESS;
3804 *type = BC_INST_SCALE_FUNC;
3805 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3807 s = bc_lex_next(&p->l);
3810 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3812 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3813 bc_parse_push(p, BC_INST_SCALE_FUNC);
3815 return bc_lex_next(&p->l);
3818 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3819 size_t *nexprs, uint8_t flags)
3824 BcInst etype = *prev;
3826 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3827 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3828 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3830 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3831 bc_parse_push(p, inst);
3832 s = bc_lex_next(&p->l);
3836 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3839 s = bc_lex_next(&p->l);
3843 // Because we parse the next part of the expression
3844 // right here, we need to increment this.
3845 *nexprs = *nexprs + 1;
3851 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3855 case BC_LEX_KEY_IBASE:
3856 case BC_LEX_KEY_LAST:
3857 case BC_LEX_KEY_OBASE:
3859 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3860 s = bc_lex_next(&p->l);
3864 case BC_LEX_KEY_SCALE:
3866 s = bc_lex_next(&p->l);
3868 if (p->l.t.t == BC_LEX_LPAREN)
3869 s = bc_error("bad token");
3871 bc_parse_push(p, BC_INST_SCALE);
3877 s = bc_error("bad token");
3882 if (!s) bc_parse_push(p, inst);
3888 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3889 bool rparen, size_t *nexprs)
3893 BcInst etype = *prev;
3895 s = bc_lex_next(&p->l);
3898 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3899 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3902 *prev = BC_PARSE_TOKEN_INST(type);
3904 // We can just push onto the op stack because this is the largest
3905 // precedence operator that gets pushed. Inc/dec does not.
3906 if (type != BC_LEX_OP_MINUS)
3907 bc_vec_push(&p->ops, &type);
3909 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3914 static BcStatus bc_parse_string(BcParse *p, char inst)
3916 char *str = xstrdup(p->l.t.v.v);
3918 bc_parse_push(p, BC_INST_STR);
3919 bc_parse_pushIndex(p, G.prog.strs.len);
3920 bc_vec_push(&G.prog.strs, &str);
3921 bc_parse_push(p, inst);
3923 return bc_lex_next(&p->l);
3926 static BcStatus bc_parse_print(BcParse *p)
3932 s = bc_lex_next(&p->l);
3937 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
3938 return bc_error("bad print statement");
3940 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3942 if (type == BC_LEX_STR)
3943 s = bc_parse_string(p, BC_INST_PRINT_POP);
3945 s = bc_parse_expr(p, 0, bc_parse_next_print);
3947 bc_parse_push(p, BC_INST_PRINT_POP);
3952 comma = p->l.t.t == BC_LEX_COMMA;
3953 if (comma) s = bc_lex_next(&p->l);
3958 if (comma) return bc_error("bad token");
3960 return bc_lex_next(&p->l);
3963 static BcStatus bc_parse_return(BcParse *p)
3969 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
3971 s = bc_lex_next(&p->l);
3975 paren = t == BC_LEX_LPAREN;
3977 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3978 bc_parse_push(p, BC_INST_RET0);
3981 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3982 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3985 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
3986 bc_parse_push(p, BC_INST_RET0);
3987 s = bc_lex_next(&p->l);
3991 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
3992 s = bc_posix_error("POSIX requires parentheses around return expressions");
3996 bc_parse_push(p, BC_INST_RET);
4002 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4004 BcStatus s = BC_STATUS_SUCCESS;
4006 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4007 return bc_error("bad token");
4011 if (p->l.t.t == BC_LEX_RBRACE) {
4012 if (!p->nbraces) return bc_error("bad token");
4014 s = bc_lex_next(&p->l);
4018 return bc_error("bad token");
4021 if (BC_PARSE_IF(p)) {
4025 while (p->l.t.t == BC_LEX_NLINE) {
4026 s = bc_lex_next(&p->l);
4030 bc_vec_pop(&p->flags);
4032 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4033 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4035 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4037 else if (BC_PARSE_ELSE(p)) {
4042 bc_vec_pop(&p->flags);
4044 ip = bc_vec_top(&p->exits);
4045 label = bc_vec_item(&p->func->labels, ip->idx);
4046 *label = p->func->code.len;
4048 bc_vec_pop(&p->exits);
4050 else if (BC_PARSE_FUNC_INNER(p)) {
4051 bc_parse_push(p, BC_INST_RET0);
4052 bc_parse_updateFunc(p, BC_PROG_MAIN);
4053 bc_vec_pop(&p->flags);
4057 BcInstPtr *ip = bc_vec_top(&p->exits);
4058 size_t *label = bc_vec_top(&p->conds);
4060 bc_parse_push(p, BC_INST_JUMP);
4061 bc_parse_pushIndex(p, *label);
4063 label = bc_vec_item(&p->func->labels, ip->idx);
4064 *label = p->func->code.len;
4066 bc_vec_pop(&p->flags);
4067 bc_vec_pop(&p->exits);
4068 bc_vec_pop(&p->conds);
4074 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4076 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4077 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4078 flags |= BC_PARSE_FLAG_BODY;
4079 bc_vec_push(&p->flags, &flags);
4082 static void bc_parse_noElse(BcParse *p)
4086 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4088 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4090 ip = bc_vec_top(&p->exits);
4091 label = bc_vec_item(&p->func->labels, ip->idx);
4092 *label = p->func->code.len;
4094 bc_vec_pop(&p->exits);
4097 static BcStatus bc_parse_if(BcParse *p)
4102 s = bc_lex_next(&p->l);
4104 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4106 s = bc_lex_next(&p->l);
4108 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4110 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4112 s = bc_lex_next(&p->l);
4114 bc_parse_push(p, BC_INST_JUMP_ZERO);
4116 ip.idx = p->func->labels.len;
4117 ip.func = ip.len = 0;
4119 bc_parse_pushIndex(p, ip.idx);
4120 bc_vec_push(&p->exits, &ip);
4121 bc_vec_push(&p->func->labels, &ip.idx);
4122 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4124 return BC_STATUS_SUCCESS;
4127 static BcStatus bc_parse_else(BcParse *p)
4131 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
4133 ip.idx = p->func->labels.len;
4134 ip.func = ip.len = 0;
4136 bc_parse_push(p, BC_INST_JUMP);
4137 bc_parse_pushIndex(p, ip.idx);
4141 bc_vec_push(&p->exits, &ip);
4142 bc_vec_push(&p->func->labels, &ip.idx);
4143 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4145 return bc_lex_next(&p->l);
4148 static BcStatus bc_parse_while(BcParse *p)
4153 s = bc_lex_next(&p->l);
4155 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4156 s = bc_lex_next(&p->l);
4159 ip.idx = p->func->labels.len;
4161 bc_vec_push(&p->func->labels, &p->func->code.len);
4162 bc_vec_push(&p->conds, &ip.idx);
4164 ip.idx = p->func->labels.len;
4168 bc_vec_push(&p->exits, &ip);
4169 bc_vec_push(&p->func->labels, &ip.idx);
4171 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4173 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4174 s = bc_lex_next(&p->l);
4177 bc_parse_push(p, BC_INST_JUMP_ZERO);
4178 bc_parse_pushIndex(p, ip.idx);
4179 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4181 return BC_STATUS_SUCCESS;
4184 static BcStatus bc_parse_for(BcParse *p)
4188 size_t cond_idx, exit_idx, body_idx, update_idx;
4190 s = bc_lex_next(&p->l);
4192 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4193 s = bc_lex_next(&p->l);
4196 if (p->l.t.t != BC_LEX_SCOLON)
4197 s = bc_parse_expr(p, 0, bc_parse_next_for);
4199 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4202 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4203 s = bc_lex_next(&p->l);
4206 cond_idx = p->func->labels.len;
4207 update_idx = cond_idx + 1;
4208 body_idx = update_idx + 1;
4209 exit_idx = body_idx + 1;
4211 bc_vec_push(&p->func->labels, &p->func->code.len);
4213 if (p->l.t.t != BC_LEX_SCOLON)
4214 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4216 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4219 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4221 s = bc_lex_next(&p->l);
4224 bc_parse_push(p, BC_INST_JUMP_ZERO);
4225 bc_parse_pushIndex(p, exit_idx);
4226 bc_parse_push(p, BC_INST_JUMP);
4227 bc_parse_pushIndex(p, body_idx);
4229 ip.idx = p->func->labels.len;
4231 bc_vec_push(&p->conds, &update_idx);
4232 bc_vec_push(&p->func->labels, &p->func->code.len);
4234 if (p->l.t.t != BC_LEX_RPAREN)
4235 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4237 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4241 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4242 bc_parse_push(p, BC_INST_JUMP);
4243 bc_parse_pushIndex(p, cond_idx);
4244 bc_vec_push(&p->func->labels, &p->func->code.len);
4250 bc_vec_push(&p->exits, &ip);
4251 bc_vec_push(&p->func->labels, &ip.idx);
4253 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4255 return BC_STATUS_SUCCESS;
4258 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4264 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
4266 if (type == BC_LEX_KEY_BREAK) {
4268 if (p->exits.len == 0) return bc_error("bad token");
4270 i = p->exits.len - 1;
4271 ip = bc_vec_item(&p->exits, i);
4273 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4274 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
4279 i = *((size_t *) bc_vec_top(&p->conds));
4281 bc_parse_push(p, BC_INST_JUMP);
4282 bc_parse_pushIndex(p, i);
4284 s = bc_lex_next(&p->l);
4287 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4288 return bc_error("bad token");
4290 return bc_lex_next(&p->l);
4293 static BcStatus bc_parse_func(BcParse *p)
4296 bool var, comma = false;
4300 s = bc_lex_next(&p->l);
4302 if (p->l.t.t != BC_LEX_NAME)
4303 return bc_error("bad function definition");
4305 name = xstrdup(p->l.t.v.v);
4306 bc_parse_addFunc(p, name, &p->fidx);
4308 s = bc_lex_next(&p->l);
4310 if (p->l.t.t != BC_LEX_LPAREN)
4311 return bc_error("bad function definition");
4312 s = bc_lex_next(&p->l);
4315 while (p->l.t.t != BC_LEX_RPAREN) {
4317 if (p->l.t.t != BC_LEX_NAME)
4318 return bc_error("bad function definition");
4322 name = xstrdup(p->l.t.v.v);
4323 s = bc_lex_next(&p->l);
4326 var = p->l.t.t != BC_LEX_LBRACKET;
4330 s = bc_lex_next(&p->l);
4333 if (p->l.t.t != BC_LEX_RBRACKET) {
4334 s = bc_error("bad function definition");
4338 s = bc_lex_next(&p->l);
4342 comma = p->l.t.t == BC_LEX_COMMA;
4344 s = bc_lex_next(&p->l);
4348 s = bc_func_insert(p->func, name, var);
4352 if (comma) return bc_error("bad function definition");
4354 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4355 bc_parse_startBody(p, flags);
4357 s = bc_lex_next(&p->l);
4360 if (p->l.t.t != BC_LEX_LBRACE)
4361 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4370 static BcStatus bc_parse_auto(BcParse *p)
4373 bool comma, var, one;
4376 if (!p->auto_part) return bc_error("bad token");
4377 s = bc_lex_next(&p->l);
4380 p->auto_part = comma = false;
4381 one = p->l.t.t == BC_LEX_NAME;
4383 while (p->l.t.t == BC_LEX_NAME) {
4385 name = xstrdup(p->l.t.v.v);
4386 s = bc_lex_next(&p->l);
4389 var = p->l.t.t != BC_LEX_LBRACKET;
4392 s = bc_lex_next(&p->l);
4395 if (p->l.t.t != BC_LEX_RBRACKET) {
4396 s = bc_error("bad function definition");
4400 s = bc_lex_next(&p->l);
4404 comma = p->l.t.t == BC_LEX_COMMA;
4406 s = bc_lex_next(&p->l);
4410 s = bc_func_insert(p->func, name, var);
4414 if (comma) return bc_error("bad function definition");
4415 if (!one) return bc_error("no auto variable found");
4417 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4418 return bc_error("bad token");
4420 return bc_lex_next(&p->l);
4427 static BcStatus bc_parse_body(BcParse *p, bool brace)
4429 BcStatus s = BC_STATUS_SUCCESS;
4430 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4432 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4434 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4436 if (!brace) return bc_error("bad token");
4437 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4439 if (!p->auto_part) {
4440 s = bc_parse_auto(p);
4444 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4447 s = bc_parse_stmt(p);
4448 if (!s && !brace) s = bc_parse_endBody(p, false);
4454 static BcStatus bc_parse_stmt(BcParse *p)
4456 BcStatus s = BC_STATUS_SUCCESS;
4462 return bc_lex_next(&p->l);
4465 case BC_LEX_KEY_ELSE:
4467 p->auto_part = false;
4473 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
4476 s = bc_lex_next(&p->l);
4479 return bc_parse_body(p, true);
4482 case BC_LEX_KEY_AUTO:
4484 return bc_parse_auto(p);
4489 p->auto_part = false;
4491 if (BC_PARSE_IF_END(p)) {
4493 return BC_STATUS_SUCCESS;
4495 else if (BC_PARSE_BODY(p))
4496 return bc_parse_body(p, false);
4506 case BC_LEX_OP_MINUS:
4507 case BC_LEX_OP_BOOL_NOT:
4511 case BC_LEX_KEY_IBASE:
4512 case BC_LEX_KEY_LAST:
4513 case BC_LEX_KEY_LENGTH:
4514 case BC_LEX_KEY_OBASE:
4515 case BC_LEX_KEY_READ:
4516 case BC_LEX_KEY_SCALE:
4517 case BC_LEX_KEY_SQRT:
4519 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4523 case BC_LEX_KEY_ELSE:
4525 s = bc_parse_else(p);
4531 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4537 s = bc_parse_endBody(p, true);
4543 s = bc_parse_string(p, BC_INST_PRINT_STR);
4547 case BC_LEX_KEY_BREAK:
4548 case BC_LEX_KEY_CONTINUE:
4550 s = bc_parse_loopExit(p, p->l.t.t);
4554 case BC_LEX_KEY_FOR:
4556 s = bc_parse_for(p);
4560 case BC_LEX_KEY_HALT:
4562 bc_parse_push(p, BC_INST_HALT);
4563 s = bc_lex_next(&p->l);
4573 case BC_LEX_KEY_LIMITS:
4575 // "limits" is a compile-time command,
4576 // the output is produced at _parse time_.
4577 s = bc_lex_next(&p->l);
4579 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4580 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4581 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4582 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4583 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4584 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4585 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4586 printf("Number of vars = %lu\n", BC_MAX_VARS);
4590 case BC_LEX_KEY_PRINT:
4592 s = bc_parse_print(p);
4596 case BC_LEX_KEY_QUIT:
4598 // "quit" is a compile-time command. For example,
4599 // "if (0 == 1) quit" terminates when parsing the statement,
4600 // not when it is executed
4604 case BC_LEX_KEY_RETURN:
4606 s = bc_parse_return(p);
4610 case BC_LEX_KEY_WHILE:
4612 s = bc_parse_while(p);
4618 s = bc_error("bad token");
4626 static BcStatus bc_parse_parse(BcParse *p)
4630 if (p->l.t.t == BC_LEX_EOF)
4631 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4632 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4633 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
4634 s = bc_parse_func(p);
4637 s = bc_parse_stmt(p);
4639 if (s || G_interrupt) {
4641 s = BC_STATUS_FAILURE;
4647 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4649 BcStatus s = BC_STATUS_SUCCESS;
4650 BcInst prev = BC_INST_PRINT;
4651 BcLexType top, t = p->l.t.t;
4652 size_t nexprs = 0, ops_bgn = p->ops.len;
4653 uint32_t i, nparens, nrelops;
4654 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4656 paren_first = p->l.t.t == BC_LEX_LPAREN;
4657 nparens = nrelops = 0;
4658 paren_expr = rprn = done = get_token = assign = false;
4661 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4667 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4668 rprn = get_token = bin_last = false;
4672 case BC_LEX_OP_MINUS:
4674 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4675 rprn = get_token = false;
4676 bin_last = prev == BC_INST_MINUS;
4680 case BC_LEX_OP_ASSIGN_POWER:
4681 case BC_LEX_OP_ASSIGN_MULTIPLY:
4682 case BC_LEX_OP_ASSIGN_DIVIDE:
4683 case BC_LEX_OP_ASSIGN_MODULUS:
4684 case BC_LEX_OP_ASSIGN_PLUS:
4685 case BC_LEX_OP_ASSIGN_MINUS:
4686 case BC_LEX_OP_ASSIGN:
4688 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4689 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4690 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4692 s = bc_error("bad assignment:"
4693 " left side must be scale,"
4694 " ibase, obase, last, var,"
4701 case BC_LEX_OP_POWER:
4702 case BC_LEX_OP_MULTIPLY:
4703 case BC_LEX_OP_DIVIDE:
4704 case BC_LEX_OP_MODULUS:
4705 case BC_LEX_OP_PLUS:
4706 case BC_LEX_OP_REL_EQ:
4707 case BC_LEX_OP_REL_LE:
4708 case BC_LEX_OP_REL_GE:
4709 case BC_LEX_OP_REL_NE:
4710 case BC_LEX_OP_REL_LT:
4711 case BC_LEX_OP_REL_GT:
4712 case BC_LEX_OP_BOOL_NOT:
4713 case BC_LEX_OP_BOOL_OR:
4714 case BC_LEX_OP_BOOL_AND:
4716 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4717 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4719 return bc_error("bad expression");
4722 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4723 prev = BC_PARSE_TOKEN_INST(t);
4724 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4725 rprn = get_token = false;
4726 bin_last = t != BC_LEX_OP_BOOL_NOT;
4733 if (BC_PARSE_LEAF(prev, rprn))
4734 return bc_error("bad expression");
4736 paren_expr = rprn = bin_last = false;
4738 bc_vec_push(&p->ops, &t);
4745 if (bin_last || prev == BC_INST_BOOL_NOT)
4746 return bc_error("bad expression");
4749 s = BC_STATUS_SUCCESS;
4754 else if (!paren_expr)
4755 return BC_STATUS_PARSE_EMPTY_EXP;
4758 paren_expr = rprn = true;
4759 get_token = bin_last = false;
4761 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4768 if (BC_PARSE_LEAF(prev, rprn))
4769 return bc_error("bad expression");
4771 rprn = get_token = bin_last = false;
4772 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4780 if (BC_PARSE_LEAF(prev, rprn))
4781 return bc_error("bad expression");
4782 bc_parse_number(p, &prev, &nexprs);
4783 paren_expr = get_token = true;
4784 rprn = bin_last = false;
4789 case BC_LEX_KEY_IBASE:
4790 case BC_LEX_KEY_LAST:
4791 case BC_LEX_KEY_OBASE:
4793 if (BC_PARSE_LEAF(prev, rprn))
4794 return bc_error("bad expression");
4795 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4796 bc_parse_push(p, (char) prev);
4798 paren_expr = get_token = true;
4799 rprn = bin_last = false;
4805 case BC_LEX_KEY_LENGTH:
4806 case BC_LEX_KEY_SQRT:
4808 if (BC_PARSE_LEAF(prev, rprn))
4809 return bc_error("bad expression");
4810 s = bc_parse_builtin(p, t, flags, &prev);
4812 rprn = get_token = bin_last = false;
4818 case BC_LEX_KEY_READ:
4820 if (BC_PARSE_LEAF(prev, rprn))
4821 return bc_error("bad expression");
4822 else if (flags & BC_PARSE_NOREAD)
4823 s = bc_error("read() call inside of a read() call");
4825 s = bc_parse_read(p);
4828 rprn = get_token = bin_last = false;
4830 prev = BC_INST_READ;
4835 case BC_LEX_KEY_SCALE:
4837 if (BC_PARSE_LEAF(prev, rprn))
4838 return bc_error("bad expression");
4839 s = bc_parse_scale(p, &prev, flags);
4841 rprn = get_token = bin_last = false;
4843 prev = BC_INST_SCALE;
4850 s = bc_error("bad token");
4855 if (!s && get_token) s = bc_lex_next(&p->l);
4859 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4861 while (p->ops.len > ops_bgn) {
4863 top = BC_PARSE_TOP_OP(p);
4864 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4866 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4867 return bc_error("bad expression");
4869 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4871 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4872 bc_vec_pop(&p->ops);
4875 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4876 return bc_error("bad expression");
4878 for (i = 0; i < next.len; ++i)
4879 if (t == next.tokens[i])
4881 return bc_error("bad expression");
4884 if (!(flags & BC_PARSE_REL) && nrelops) {
4885 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
4888 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4889 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
4893 if (flags & BC_PARSE_PRINT) {
4894 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4895 bc_parse_push(p, BC_INST_POP);
4901 static void bc_parse_init(BcParse *p, size_t func)
4903 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4906 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4908 return bc_parse_expr(p, flags, bc_parse_next_read);
4913 static BcStatus dc_parse_register(BcParse *p)
4918 s = bc_lex_next(&p->l);
4920 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
4922 name = xstrdup(p->l.t.v.v);
4923 bc_parse_pushName(p, name);
4928 static BcStatus dc_parse_string(BcParse *p)
4930 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
4931 size_t idx, len = G.prog.strs.len;
4933 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4936 str = xstrdup(p->l.t.v.v);
4937 bc_parse_push(p, BC_INST_STR);
4938 bc_parse_pushIndex(p, len);
4939 bc_vec_push(&G.prog.strs, &str);
4940 bc_parse_addFunc(p, name, &idx);
4942 return bc_lex_next(&p->l);
4945 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4949 bc_parse_push(p, inst);
4951 s = dc_parse_register(p);
4956 bc_parse_push(p, BC_INST_SWAP);
4957 bc_parse_push(p, BC_INST_ASSIGN);
4958 bc_parse_push(p, BC_INST_POP);
4961 return bc_lex_next(&p->l);
4964 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4968 bc_parse_push(p, inst);
4969 bc_parse_push(p, BC_INST_EXEC_COND);
4971 s = dc_parse_register(p);
4974 s = bc_lex_next(&p->l);
4977 if (p->l.t.t == BC_LEX_ELSE) {
4978 s = dc_parse_register(p);
4980 s = bc_lex_next(&p->l);
4983 bc_parse_push(p, BC_PARSE_STREND);
4988 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4990 BcStatus s = BC_STATUS_SUCCESS;
4993 bool assign, get_token = false;
4997 case BC_LEX_OP_REL_EQ:
4998 case BC_LEX_OP_REL_LE:
4999 case BC_LEX_OP_REL_GE:
5000 case BC_LEX_OP_REL_NE:
5001 case BC_LEX_OP_REL_LT:
5002 case BC_LEX_OP_REL_GT:
5004 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5011 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5017 s = dc_parse_string(p);
5024 if (t == BC_LEX_NEG) {
5025 s = bc_lex_next(&p->l);
5027 if (p->l.t.t != BC_LEX_NUMBER)
5028 return bc_error("bad token");
5031 bc_parse_number(p, &prev, &p->nbraces);
5033 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5039 case BC_LEX_KEY_READ:
5041 if (flags & BC_PARSE_NOREAD)
5042 s = bc_error("read() call inside of a read() call");
5044 bc_parse_push(p, BC_INST_READ);
5049 case BC_LEX_OP_ASSIGN:
5050 case BC_LEX_STORE_PUSH:
5052 assign = t == BC_LEX_OP_ASSIGN;
5053 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5054 s = dc_parse_mem(p, inst, true, assign);
5059 case BC_LEX_LOAD_POP:
5061 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5062 s = dc_parse_mem(p, inst, true, false);
5066 case BC_LEX_STORE_IBASE:
5067 case BC_LEX_STORE_SCALE:
5068 case BC_LEX_STORE_OBASE:
5070 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5071 s = dc_parse_mem(p, inst, false, true);
5077 s = bc_error("bad token");
5083 if (!s && get_token) s = bc_lex_next(&p->l);
5088 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5090 BcStatus s = BC_STATUS_SUCCESS;
5094 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5096 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5098 inst = dc_parse_insts[t];
5100 if (inst != BC_INST_INVALID) {
5101 bc_parse_push(p, inst);
5102 s = bc_lex_next(&p->l);
5105 s = dc_parse_token(p, t, flags);
5108 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5109 bc_parse_push(p, BC_INST_POP_EXEC);
5114 static BcStatus dc_parse_parse(BcParse *p)
5118 if (p->l.t.t == BC_LEX_EOF)
5119 s = bc_error("end of file");
5121 s = dc_parse_expr(p, 0);
5123 if (s || G_interrupt) {
5125 s = BC_STATUS_FAILURE;
5131 static void dc_parse_init(BcParse *p, size_t func)
5133 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5137 static void common_parse_init(BcParse *p, size_t func)
5140 bc_parse_init(p, func);
5142 dc_parse_init(p, func);
5146 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5149 return bc_parse_expression(p, flags);
5151 return dc_parse_expr(p, flags);
5155 static BcVec* bc_program_search(char *id, bool var)
5163 v = var ? &G.prog.vars : &G.prog.arrs;
5164 map = var ? &G.prog.var_map : &G.prog.arr_map;
5168 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5171 bc_array_init(&data.v, var);
5172 bc_vec_push(v, &data.v);
5175 ptr = bc_vec_item(map, i);
5176 if (new) ptr->name = xstrdup(e.name);
5177 return bc_vec_item(v, ptr->idx);
5180 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5182 BcStatus s = BC_STATUS_SUCCESS;
5187 case BC_RESULT_TEMP:
5188 case BC_RESULT_IBASE:
5189 case BC_RESULT_SCALE:
5190 case BC_RESULT_OBASE:
5196 case BC_RESULT_CONSTANT:
5198 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5199 size_t base_t, len = strlen(*str);
5202 bc_num_init(&r->d.n, len);
5204 hex = hex && len == 1;
5205 base = hex ? &G.prog.hexb : &G.prog.ib;
5206 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5207 s = bc_num_parse(&r->d.n, *str, base, base_t);
5210 bc_num_free(&r->d.n);
5215 r->t = BC_RESULT_TEMP;
5221 case BC_RESULT_ARRAY:
5222 case BC_RESULT_ARRAY_ELEM:
5226 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5228 if (r->t == BC_RESULT_ARRAY_ELEM) {
5230 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5231 *num = bc_vec_item(v, r->d.id.idx);
5234 *num = bc_vec_top(v);
5239 case BC_RESULT_LAST:
5241 *num = &G.prog.last;
5255 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5256 BcResult **r, BcNum **rn, bool assign)
5260 BcResultType lt, rt;
5262 if (!BC_PROG_STACK(&G.prog.results, 2))
5263 return bc_error("stack has too few elements");
5265 *r = bc_vec_item_rev(&G.prog.results, 0);
5266 *l = bc_vec_item_rev(&G.prog.results, 1);
5270 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5272 s = bc_program_num(*l, ln, false);
5274 s = bc_program_num(*r, rn, hex);
5277 // We run this again under these conditions in case any vector has been
5278 // reallocated out from under the BcNums or arrays we had.
5279 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5280 s = bc_program_num(*l, ln, false);
5284 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5285 return bc_error("variable is wrong type");
5286 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5287 return bc_error("variable is wrong type");
5292 static void bc_program_binOpRetire(BcResult *r)
5294 r->t = BC_RESULT_TEMP;
5295 bc_vec_pop(&G.prog.results);
5296 bc_vec_pop(&G.prog.results);
5297 bc_vec_push(&G.prog.results, r);
5300 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5304 if (!BC_PROG_STACK(&G.prog.results, 1))
5305 return bc_error("stack has too few elements");
5306 *r = bc_vec_top(&G.prog.results);
5308 s = bc_program_num(*r, n, false);
5311 if (!BC_PROG_NUM((*r), (*n)))
5312 return bc_error("variable is wrong type");
5317 static void bc_program_retire(BcResult *r, BcResultType t)
5320 bc_vec_pop(&G.prog.results);
5321 bc_vec_push(&G.prog.results, r);
5324 static BcStatus bc_program_op(char inst)
5327 BcResult *opd1, *opd2, res;
5328 BcNum *n1, *n2 = NULL;
5330 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5332 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5334 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5336 bc_program_binOpRetire(&res);
5341 bc_num_free(&res.d.n);
5345 static BcStatus bc_program_read(void)
5352 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5354 for (i = 0; i < G.prog.stack.len; ++i) {
5355 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5356 if (ip_ptr->func == BC_PROG_READ)
5357 return bc_error("read() call inside of a read() call");
5360 bc_vec_pop_all(&f->code);
5361 bc_char_vec_init(&buf);
5363 s = bc_read_line(&buf, "read> ");
5366 common_parse_init(&parse, BC_PROG_READ);
5367 bc_lex_file(&parse.l, bc_program_stdin_name);
5369 s = bc_parse_text(&parse, buf.v);
5370 if (s) goto exec_err;
5371 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5372 if (s) goto exec_err;
5374 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5375 s = bc_error("bad read() expression");
5379 ip.func = BC_PROG_READ;
5381 ip.len = G.prog.results.len;
5383 // Update this pointer, just in case.
5384 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5386 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5387 bc_vec_push(&G.prog.stack, &ip);
5390 bc_parse_free(&parse);
5396 static size_t bc_program_index(char *code, size_t *bgn)
5398 char amt = code[(*bgn)++], i = 0;
5401 for (; i < amt; ++i, ++(*bgn))
5402 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5407 static char *bc_program_name(char *code, size_t *bgn)
5410 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5412 s = xmalloc(ptr - str + 1);
5415 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5423 static void bc_program_printString(const char *str, size_t *nchars)
5425 size_t i, len = strlen(str);
5434 for (i = 0; i < len; ++i, ++(*nchars)) {
5438 if (c != '\\' || i == len - 1)
5498 // Just print the backslash and following character.
5509 static BcStatus bc_program_print(char inst, size_t idx)
5511 BcStatus s = BC_STATUS_SUCCESS;
5516 bool pop = inst != BC_INST_PRINT;
5518 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5519 return bc_error("stack has too few elements");
5521 r = bc_vec_item_rev(&G.prog.results, idx);
5522 s = bc_program_num(r, &num, false);
5525 if (BC_PROG_NUM(r, num)) {
5526 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5527 if (!s) bc_num_copy(&G.prog.last, num);
5531 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5532 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5534 if (inst == BC_INST_PRINT_STR) {
5535 for (i = 0, len = strlen(str); i < len; ++i) {
5538 if (c == '\n') G.prog.nchars = SIZE_MAX;
5543 bc_program_printString(str, &G.prog.nchars);
5544 if (inst == BC_INST_PRINT) bb_putchar('\n');
5548 if (!s && pop) bc_vec_pop(&G.prog.results);
5553 static BcStatus bc_program_negate(void)
5559 s = bc_program_prep(&ptr, &num);
5562 bc_num_init(&res.d.n, num->len);
5563 bc_num_copy(&res.d.n, num);
5564 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5566 bc_program_retire(&res, BC_RESULT_TEMP);
5571 static BcStatus bc_program_logical(char inst)
5574 BcResult *opd1, *opd2, res;
5579 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5581 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5583 if (inst == BC_INST_BOOL_AND)
5584 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5585 else if (inst == BC_INST_BOOL_OR)
5586 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5589 cmp = bc_num_cmp(n1, n2);
5593 case BC_INST_REL_EQ:
5599 case BC_INST_REL_LE:
5605 case BC_INST_REL_GE:
5611 case BC_INST_REL_NE:
5617 case BC_INST_REL_LT:
5623 case BC_INST_REL_GT:
5631 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5633 bc_program_binOpRetire(&res);
5639 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5645 memset(&n2, 0, sizeof(BcNum));
5646 n2.rdx = res.d.id.idx = r->d.id.idx;
5647 res.t = BC_RESULT_STR;
5650 if (!BC_PROG_STACK(&G.prog.results, 2))
5651 return bc_error("stack has too few elements");
5653 bc_vec_pop(&G.prog.results);
5656 bc_vec_pop(&G.prog.results);
5658 bc_vec_push(&G.prog.results, &res);
5659 bc_vec_push(v, &n2);
5661 return BC_STATUS_SUCCESS;
5665 static BcStatus bc_program_copyToVar(char *name, bool var)
5672 if (!BC_PROG_STACK(&G.prog.results, 1))
5673 return bc_error("stack has too few elements");
5675 ptr = bc_vec_top(&G.prog.results);
5676 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5677 return bc_error("variable is wrong type");
5678 v = bc_program_search(name, var);
5681 if (ptr->t == BC_RESULT_STR && !var)
5682 return bc_error("variable is wrong type");
5683 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5686 s = bc_program_num(ptr, &n, false);
5689 // Do this once more to make sure that pointers were not invalidated.
5690 v = bc_program_search(name, var);
5693 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5694 bc_num_copy(&r.d.n, n);
5697 bc_array_init(&r.d.v, true);
5698 bc_array_copy(&r.d.v, (BcVec *) n);
5701 bc_vec_push(v, &r.d);
5702 bc_vec_pop(&G.prog.results);
5707 static BcStatus bc_program_assign(char inst)
5710 BcResult *left, *right, res;
5711 BcNum *l = NULL, *r = NULL;
5712 unsigned long val, max;
5713 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5715 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5718 ib = left->t == BC_RESULT_IBASE;
5719 sc = left->t == BC_RESULT_SCALE;
5723 if (right->t == BC_RESULT_STR) {
5727 if (left->t != BC_RESULT_VAR)
5728 return bc_error("variable is wrong type");
5729 v = bc_program_search(left->d.id.name, true);
5731 return bc_program_assignStr(right, v, false);
5735 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5736 return bc_error("bad assignment:"
5737 " left side must be scale,"
5738 " ibase, obase, last, var,"
5743 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5744 return bc_error("divide by zero");
5749 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5756 if (ib || sc || left->t == BC_RESULT_OBASE) {
5757 static const char *const msg[] = {
5758 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5759 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5760 "?1", //BC_RESULT_LAST
5761 "?2", //BC_RESULT_CONSTANT
5762 "?3", //BC_RESULT_ONE
5763 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5767 s = bc_num_ulong(l, &val);
5770 s = left->t - BC_RESULT_IBASE;
5773 ptr = &G.prog.scale;
5776 if (val < BC_NUM_MIN_BASE)
5777 return bc_error(msg[s]);
5778 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5779 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5783 return bc_error(msg[s]);
5785 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5787 *ptr = (size_t) val;
5788 s = BC_STATUS_SUCCESS;
5791 bc_num_init(&res.d.n, l->len);
5792 bc_num_copy(&res.d.n, l);
5793 bc_program_binOpRetire(&res);
5799 #define bc_program_pushVar(code, bgn, pop, copy) \
5800 bc_program_pushVar(code, bgn)
5801 // for bc, 'pop' and 'copy' are always false
5803 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5804 bool pop, bool copy)
5806 BcStatus s = BC_STATUS_SUCCESS;
5808 char *name = bc_program_name(code, bgn);
5810 r.t = BC_RESULT_VAR;
5815 BcVec *v = bc_program_search(name, true);
5816 BcNum *num = bc_vec_top(v);
5820 if (!BC_PROG_STACK(v, 2 - copy)) {
5822 return bc_error("stack has too few elements");
5828 if (!BC_PROG_STR(num)) {
5830 r.t = BC_RESULT_TEMP;
5832 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5833 bc_num_copy(&r.d.n, num);
5836 r.t = BC_RESULT_STR;
5837 r.d.id.idx = num->rdx;
5840 if (!copy) bc_vec_pop(v);
5845 bc_vec_push(&G.prog.results, &r);
5850 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5853 BcStatus s = BC_STATUS_SUCCESS;
5857 r.d.id.name = bc_program_name(code, bgn);
5859 if (inst == BC_INST_ARRAY) {
5860 r.t = BC_RESULT_ARRAY;
5861 bc_vec_push(&G.prog.results, &r);
5868 s = bc_program_prep(&operand, &num);
5870 s = bc_num_ulong(num, &temp);
5873 if (temp > BC_MAX_DIM) {
5874 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5878 r.d.id.idx = (size_t) temp;
5879 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5883 if (s) free(r.d.id.name);
5888 static BcStatus bc_program_incdec(char inst)
5891 BcResult *ptr, res, copy;
5895 s = bc_program_prep(&ptr, &num);
5898 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5899 copy.t = BC_RESULT_TEMP;
5900 bc_num_init(©.d.n, num->len);
5901 bc_num_copy(©.d.n, num);
5904 res.t = BC_RESULT_ONE;
5905 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5906 BC_INST_ASSIGN_PLUS :
5907 BC_INST_ASSIGN_MINUS;
5909 bc_vec_push(&G.prog.results, &res);
5910 bc_program_assign(inst);
5912 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5913 bc_vec_pop(&G.prog.results);
5914 bc_vec_push(&G.prog.results, ©);
5920 static BcStatus bc_program_call(char *code, size_t *idx)
5922 BcStatus s = BC_STATUS_SUCCESS;
5924 size_t i, nparams = bc_program_index(code, idx);
5931 ip.func = bc_program_index(code, idx);
5932 func = bc_vec_item(&G.prog.fns, ip.func);
5934 if (func->code.len == 0) {
5935 return bc_error("undefined function");
5937 if (nparams != func->nparams) {
5938 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5940 ip.len = G.prog.results.len - nparams;
5942 for (i = 0; i < nparams; ++i) {
5944 a = bc_vec_item(&func->autos, nparams - 1 - i);
5945 arg = bc_vec_top(&G.prog.results);
5947 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
5948 return bc_error("variable is wrong type");
5950 s = bc_program_copyToVar(a->name, a->idx);
5954 for (; i < func->autos.len; ++i) {
5957 a = bc_vec_item(&func->autos, i);
5958 v = bc_program_search(a->name, a->idx);
5961 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
5962 bc_vec_push(v, ¶m.n);
5965 bc_array_init(¶m.v, true);
5966 bc_vec_push(v, ¶m.v);
5970 bc_vec_push(&G.prog.stack, &ip);
5972 return BC_STATUS_SUCCESS;
5975 static BcStatus bc_program_return(char inst)
5981 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
5983 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
5984 return bc_error("stack has too few elements");
5986 f = bc_vec_item(&G.prog.fns, ip->func);
5987 res.t = BC_RESULT_TEMP;
5989 if (inst == BC_INST_RET) {
5992 BcResult *operand = bc_vec_top(&G.prog.results);
5994 s = bc_program_num(operand, &num, false);
5996 bc_num_init(&res.d.n, num->len);
5997 bc_num_copy(&res.d.n, num);
6000 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6001 bc_num_zero(&res.d.n);
6004 // We need to pop arguments as well, so this takes that into account.
6005 for (i = 0; i < f->autos.len; ++i) {
6008 BcId *a = bc_vec_item(&f->autos, i);
6010 v = bc_program_search(a->name, a->idx);
6014 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6015 bc_vec_push(&G.prog.results, &res);
6016 bc_vec_pop(&G.prog.stack);
6018 return BC_STATUS_SUCCESS;
6022 static unsigned long bc_program_scale(BcNum *n)
6024 return (unsigned long) n->rdx;
6027 static unsigned long bc_program_len(BcNum *n)
6029 unsigned long len = n->len;
6032 if (n->rdx != n->len) return len;
6033 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6038 static BcStatus bc_program_builtin(char inst)
6044 bool len = inst == BC_INST_LENGTH;
6046 if (!BC_PROG_STACK(&G.prog.results, 1))
6047 return bc_error("stack has too few elements");
6048 opnd = bc_vec_top(&G.prog.results);
6050 s = bc_program_num(opnd, &num, false);
6054 if (!BC_PROG_NUM(opnd, num) && !len)
6055 return bc_error("variable is wrong type");
6058 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6060 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6062 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6063 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6067 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6070 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6072 str = bc_vec_item(&G.prog.strs, idx);
6073 bc_num_ulong2num(&res.d.n, strlen(*str));
6077 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6078 bc_num_ulong2num(&res.d.n, f(num));
6081 bc_program_retire(&res, BC_RESULT_TEMP);
6087 static BcStatus bc_program_divmod(void)
6090 BcResult *opd1, *opd2, res, res2;
6091 BcNum *n1, *n2 = NULL;
6093 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6096 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6097 bc_num_init(&res2.d.n, n2->len);
6099 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6102 bc_program_binOpRetire(&res2);
6103 res.t = BC_RESULT_TEMP;
6104 bc_vec_push(&G.prog.results, &res);
6109 bc_num_free(&res2.d.n);
6110 bc_num_free(&res.d.n);
6114 static BcStatus bc_program_modexp(void)
6117 BcResult *r1, *r2, *r3, res;
6118 BcNum *n1, *n2, *n3;
6120 if (!BC_PROG_STACK(&G.prog.results, 3))
6121 return bc_error("stack has too few elements");
6122 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6125 r1 = bc_vec_item_rev(&G.prog.results, 2);
6126 s = bc_program_num(r1, &n1, false);
6128 if (!BC_PROG_NUM(r1, n1))
6129 return bc_error("variable is wrong type");
6131 // Make sure that the values have their pointers updated, if necessary.
6132 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6134 if (r1->t == r2->t) {
6135 s = bc_program_num(r2, &n2, false);
6139 if (r1->t == r3->t) {
6140 s = bc_program_num(r3, &n3, false);
6145 bc_num_init(&res.d.n, n3->len);
6146 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6149 bc_vec_pop(&G.prog.results);
6150 bc_program_binOpRetire(&res);
6155 bc_num_free(&res.d.n);
6159 static void bc_program_stackLen(void)
6162 size_t len = G.prog.results.len;
6164 res.t = BC_RESULT_TEMP;
6166 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6167 bc_num_ulong2num(&res.d.n, len);
6168 bc_vec_push(&G.prog.results, &res);
6171 static BcStatus bc_program_asciify(void)
6175 BcNum *num = NULL, n;
6176 char *str, *str2, c;
6177 size_t len = G.prog.strs.len, idx;
6180 if (!BC_PROG_STACK(&G.prog.results, 1))
6181 return bc_error("stack has too few elements");
6182 r = bc_vec_top(&G.prog.results);
6184 s = bc_program_num(r, &num, false);
6187 if (BC_PROG_NUM(r, num)) {
6189 bc_num_init(&n, BC_NUM_DEF_SIZE);
6190 bc_num_copy(&n, num);
6191 bc_num_truncate(&n, n.rdx);
6193 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6194 if (s) goto num_err;
6195 s = bc_num_ulong(&n, &val);
6196 if (s) goto num_err;
6203 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6204 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6212 str2 = xstrdup(str);
6213 bc_program_addFunc(str2, &idx);
6215 if (idx != len + BC_PROG_REQ_FUNCS) {
6217 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6218 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6227 bc_vec_push(&G.prog.strs, &str);
6229 res.t = BC_RESULT_STR;
6231 bc_vec_pop(&G.prog.results);
6232 bc_vec_push(&G.prog.results, &res);
6234 return BC_STATUS_SUCCESS;
6241 static BcStatus bc_program_printStream(void)
6249 if (!BC_PROG_STACK(&G.prog.results, 1))
6250 return bc_error("stack has too few elements");
6251 r = bc_vec_top(&G.prog.results);
6253 s = bc_program_num(r, &n, false);
6256 if (BC_PROG_NUM(r, n))
6257 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6259 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6260 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6267 static BcStatus bc_program_nquit(void)
6274 s = bc_program_prep(&opnd, &num);
6276 s = bc_num_ulong(num, &val);
6279 bc_vec_pop(&G.prog.results);
6281 if (G.prog.stack.len < val)
6282 return bc_error("stack has too few elements");
6283 if (G.prog.stack.len == val)
6286 bc_vec_npop(&G.prog.stack, val);
6291 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6294 BcStatus s = BC_STATUS_SUCCESS;
6304 if (!BC_PROG_STACK(&G.prog.results, 1))
6305 return bc_error("stack has too few elements");
6307 r = bc_vec_top(&G.prog.results);
6311 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6313 if (code[*bgn] == BC_PARSE_STREND)
6316 else_name = bc_program_name(code, bgn);
6318 exec = r->d.n.len != 0;
6322 else if (else_name != NULL) {
6329 v = bc_program_search(name, true);
6336 if (!exec) goto exit;
6337 if (!BC_PROG_STR(n)) {
6338 s = bc_error("variable is wrong type");
6346 if (r->t == BC_RESULT_STR)
6348 else if (r->t == BC_RESULT_VAR) {
6349 s = bc_program_num(r, &n, false);
6350 if (s || !BC_PROG_STR(n)) goto exit;
6357 fidx = sidx + BC_PROG_REQ_FUNCS;
6359 str = bc_vec_item(&G.prog.strs, sidx);
6360 f = bc_vec_item(&G.prog.fns, fidx);
6362 if (f->code.len == 0) {
6363 common_parse_init(&prs, fidx);
6364 s = bc_parse_text(&prs, *str);
6366 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6369 if (prs.l.t.t != BC_LEX_EOF) {
6370 s = bc_error("bad expression");
6374 bc_parse_free(&prs);
6378 ip.len = G.prog.results.len;
6381 bc_vec_pop(&G.prog.results);
6382 bc_vec_push(&G.prog.stack, &ip);
6384 return BC_STATUS_SUCCESS;
6387 bc_parse_free(&prs);
6388 f = bc_vec_item(&G.prog.fns, fidx);
6389 bc_vec_pop_all(&f->code);
6391 bc_vec_pop(&G.prog.results);
6396 static void bc_program_pushGlobal(char inst)
6401 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6402 if (inst == BC_INST_IBASE)
6403 val = (unsigned long) G.prog.ib_t;
6404 else if (inst == BC_INST_SCALE)
6405 val = (unsigned long) G.prog.scale;
6407 val = (unsigned long) G.prog.ob_t;
6409 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6410 bc_num_ulong2num(&res.d.n, val);
6411 bc_vec_push(&G.prog.results, &res);
6414 static void bc_program_addFunc(char *name, size_t *idx)
6416 BcId entry, *entry_ptr;
6421 entry.idx = G.prog.fns.len;
6423 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6424 if (!inserted) free(name);
6426 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6427 *idx = entry_ptr->idx;
6431 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6433 // We need to reset these, so the function can be repopulated.
6435 bc_vec_pop_all(&func->autos);
6436 bc_vec_pop_all(&func->code);
6437 bc_vec_pop_all(&func->labels);
6441 bc_vec_push(&G.prog.fns, &f);
6445 // Called when parsing or execution detects a failure,
6446 // resets execution structures.
6447 static void bc_program_reset(void)
6452 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6453 bc_vec_pop_all(&G.prog.results);
6455 f = bc_vec_item(&G.prog.fns, 0);
6456 ip = bc_vec_top(&G.prog.stack);
6457 ip->idx = f->code.len;
6459 // If !tty, no need to check for ^C: we don't have ^C handler,
6460 // we would be killed by a signal and won't reach this place
6463 static BcStatus bc_program_exec(void)
6465 BcStatus s = BC_STATUS_SUCCESS;
6469 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6470 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6471 char *code = func->code.v;
6474 while (!s && ip->idx < func->code.len) {
6476 char inst = code[(ip->idx)++];
6481 case BC_INST_JUMP_ZERO:
6483 s = bc_program_prep(&ptr, &num);
6485 cond = !bc_num_cmp(num, &G.prog.zero);
6486 bc_vec_pop(&G.prog.results);
6492 idx = bc_program_index(code, &ip->idx);
6493 addr = bc_vec_item(&func->labels, idx);
6494 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6500 s = bc_program_call(code, &ip->idx);
6504 case BC_INST_INC_PRE:
6505 case BC_INST_DEC_PRE:
6506 case BC_INST_INC_POST:
6507 case BC_INST_DEC_POST:
6509 s = bc_program_incdec(inst);
6522 s = bc_program_return(inst);
6526 case BC_INST_BOOL_OR:
6527 case BC_INST_BOOL_AND:
6529 case BC_INST_REL_EQ:
6530 case BC_INST_REL_LE:
6531 case BC_INST_REL_GE:
6532 case BC_INST_REL_NE:
6533 case BC_INST_REL_LT:
6534 case BC_INST_REL_GT:
6536 s = bc_program_logical(inst);
6542 s = bc_program_read();
6548 s = bc_program_pushVar(code, &ip->idx, false, false);
6552 case BC_INST_ARRAY_ELEM:
6555 s = bc_program_pushArray(code, &ip->idx, inst);
6561 r.t = BC_RESULT_LAST;
6562 bc_vec_push(&G.prog.results, &r);
6570 bc_program_pushGlobal(inst);
6574 case BC_INST_SCALE_FUNC:
6575 case BC_INST_LENGTH:
6578 s = bc_program_builtin(inst);
6584 r.t = BC_RESULT_CONSTANT;
6585 r.d.id.idx = bc_program_index(code, &ip->idx);
6586 bc_vec_push(&G.prog.results, &r);
6592 if (!BC_PROG_STACK(&G.prog.results, 1))
6593 s = bc_error("stack has too few elements");
6595 bc_vec_pop(&G.prog.results);
6599 case BC_INST_POP_EXEC:
6601 bc_vec_pop(&G.prog.stack);
6606 case BC_INST_PRINT_POP:
6607 case BC_INST_PRINT_STR:
6609 s = bc_program_print(inst, 0);
6615 r.t = BC_RESULT_STR;
6616 r.d.id.idx = bc_program_index(code, &ip->idx);
6617 bc_vec_push(&G.prog.results, &r);
6622 case BC_INST_MULTIPLY:
6623 case BC_INST_DIVIDE:
6624 case BC_INST_MODULUS:
6628 s = bc_program_op(inst);
6632 case BC_INST_BOOL_NOT:
6634 s = bc_program_prep(&ptr, &num);
6637 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6638 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6639 bc_program_retire(&r, BC_RESULT_TEMP);
6646 s = bc_program_negate();
6651 case BC_INST_ASSIGN_POWER:
6652 case BC_INST_ASSIGN_MULTIPLY:
6653 case BC_INST_ASSIGN_DIVIDE:
6654 case BC_INST_ASSIGN_MODULUS:
6655 case BC_INST_ASSIGN_PLUS:
6656 case BC_INST_ASSIGN_MINUS:
6658 case BC_INST_ASSIGN:
6660 s = bc_program_assign(inst);
6664 case BC_INST_MODEXP:
6666 s = bc_program_modexp();
6670 case BC_INST_DIVMOD:
6672 s = bc_program_divmod();
6676 case BC_INST_EXECUTE:
6677 case BC_INST_EXEC_COND:
6679 cond = inst == BC_INST_EXEC_COND;
6680 s = bc_program_execStr(code, &ip->idx, cond);
6684 case BC_INST_PRINT_STACK:
6686 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6687 s = bc_program_print(BC_INST_PRINT, idx);
6691 case BC_INST_CLEAR_STACK:
6693 bc_vec_pop_all(&G.prog.results);
6697 case BC_INST_STACK_LEN:
6699 bc_program_stackLen();
6703 case BC_INST_DUPLICATE:
6705 if (!BC_PROG_STACK(&G.prog.results, 1))
6706 return bc_error("stack has too few elements");
6707 ptr = bc_vec_top(&G.prog.results);
6708 bc_result_copy(&r, ptr);
6709 bc_vec_push(&G.prog.results, &r);
6717 if (!BC_PROG_STACK(&G.prog.results, 2))
6718 return bc_error("stack has too few elements");
6720 ptr = bc_vec_item_rev(&G.prog.results, 0);
6721 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6722 memcpy(&r, ptr, sizeof(BcResult));
6723 memcpy(ptr, ptr2, sizeof(BcResult));
6724 memcpy(ptr2, &r, sizeof(BcResult));
6729 case BC_INST_ASCIIFY:
6731 s = bc_program_asciify();
6735 case BC_INST_PRINT_STREAM:
6737 s = bc_program_printStream();
6742 case BC_INST_PUSH_VAR:
6744 bool copy = inst == BC_INST_LOAD;
6745 s = bc_program_pushVar(code, &ip->idx, true, copy);
6749 case BC_INST_PUSH_TO_VAR:
6751 char *name = bc_program_name(code, &ip->idx);
6752 s = bc_program_copyToVar(name, true);
6759 if (G.prog.stack.len <= 2)
6761 bc_vec_npop(&G.prog.stack, 2);
6767 s = bc_program_nquit();
6773 if (s || G_interrupt) {
6778 // If the stack has changed, pointers may be invalid.
6779 ip = bc_vec_top(&G.prog.stack);
6780 func = bc_vec_item(&G.prog.fns, ip->func);
6781 code = func->code.v;
6787 static void bc_vm_info(void)
6789 printf("%s "BB_VER"\n"
6790 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6791 "Report bugs at: https://github.com/gavinhoward/bc\n"
6792 "This is free software with ABSOLUTELY NO WARRANTY\n"
6797 static void bc_vm_envArgs(void)
6799 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6802 char *env_args = getenv(bc_args_env_name), *buf;
6804 if (!env_args) return;
6806 G.env_args = xstrdup(env_args);
6809 bc_vec_init(&v, sizeof(char *), NULL);
6810 bc_vec_push(&v, &bc_args_env_name);
6813 if (!isspace(*buf)) {
6814 bc_vec_push(&v, &buf);
6815 while (*buf != 0 && !isspace(*buf)) ++buf;
6816 if (*buf != 0) (*(buf++)) = '\0';
6822 bc_args((int) v.len, (char **) v.v);
6828 static size_t bc_vm_envLen(const char *var)
6830 char *lenv = getenv(var);
6831 size_t i, len = BC_NUM_PRINT_WIDTH;
6834 if (!lenv) return len;
6838 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6840 len = (size_t) atoi(lenv) - 1;
6841 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6844 len = BC_NUM_PRINT_WIDTH;
6849 static BcStatus bc_vm_process(const char *text)
6851 BcStatus s = bc_parse_text(&G.prs, text);
6855 while (G.prs.l.t.t != BC_LEX_EOF) {
6856 s = G.prs.parse(&G.prs);
6860 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6861 s = bc_program_exec();
6870 static BcStatus bc_vm_file(const char *file)
6878 data = bc_read_file(file);
6879 if (!data) return bc_error("file '%s' is not text", file);
6881 bc_lex_file(&G.prs.l, file);
6882 s = bc_vm_process(data);
6885 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6886 ip = bc_vec_item(&G.prog.stack, 0);
6888 if (main_func->code.len < ip->idx)
6889 s = bc_error("file '%s' is not executable", file);
6896 static BcStatus bc_vm_stdin(void)
6900 size_t len, i, str = 0;
6901 bool comment = false;
6903 G.prog.file = bc_program_stdin_name;
6904 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6906 bc_char_vec_init(&buffer);
6907 bc_char_vec_init(&buf);
6908 bc_vec_pushByte(&buffer, '\0');
6910 // This loop is complex because the vm tries not to send any lines that end
6911 // with a backslash to the parser. The reason for that is because the parser
6912 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6913 // case, and for strings and comments, the parser will expect more stuff.
6914 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
6916 char *string = buf.v;
6921 if (str && buf.v[0] == G.send)
6923 else if (buf.v[0] == G.sbgn)
6926 else if (len > 1 || comment) {
6928 for (i = 0; i < len; ++i) {
6930 bool notend = len > i + 1;
6933 if (i - 1 > len || string[i - 1] != '\\') {
6934 if (G.sbgn == G.send)
6936 else if (c == G.send)
6938 else if (c == G.sbgn)
6942 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6946 else if (c == '*' && notend && comment && string[i + 1] == '/')
6950 if (str || comment || string[len - 2] == '\\') {
6951 bc_vec_concat(&buffer, buf.v);
6956 bc_vec_concat(&buffer, buf.v);
6957 s = bc_vm_process(buffer.v);
6960 fputs("ready for more input\n", stderr);
6963 bc_vec_pop_all(&buffer);
6967 s = bc_error("string end could not be found");
6970 s = bc_error("comment end could not be found");
6974 bc_vec_free(&buffer);
6978 static BcStatus bc_vm_exec(void)
6980 BcStatus s = BC_STATUS_SUCCESS;
6984 if (option_mask32 & BC_FLAG_L) {
6986 bc_lex_file(&G.prs.l, bc_lib_name);
6987 s = bc_parse_text(&G.prs, bc_lib);
6989 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6990 s = G.prs.parse(&G.prs);
6993 s = bc_program_exec();
6998 for (i = 0; !s && i < G.files.len; ++i)
6999 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7002 fputs("ready for more input\n", stderr);
7005 if (IS_BC || !G.files.len)
7007 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7008 s = bc_vm_process("");
7013 #if ENABLE_FEATURE_CLEAN_UP
7014 static void bc_program_free()
7016 bc_num_free(&G.prog.ib);
7017 bc_num_free(&G.prog.ob);
7018 bc_num_free(&G.prog.hexb);
7020 bc_num_free(&G.prog.strmb);
7022 bc_vec_free(&G.prog.fns);
7023 bc_vec_free(&G.prog.fn_map);
7024 bc_vec_free(&G.prog.vars);
7025 bc_vec_free(&G.prog.var_map);
7026 bc_vec_free(&G.prog.arrs);
7027 bc_vec_free(&G.prog.arr_map);
7028 bc_vec_free(&G.prog.strs);
7029 bc_vec_free(&G.prog.consts);
7030 bc_vec_free(&G.prog.results);
7031 bc_vec_free(&G.prog.stack);
7032 bc_num_free(&G.prog.last);
7033 bc_num_free(&G.prog.zero);
7034 bc_num_free(&G.prog.one);
7037 static void bc_vm_free(void)
7039 bc_vec_free(&G.files);
7041 bc_parse_free(&G.prs);
7046 static void bc_program_init(size_t line_len)
7051 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7052 memset(&ip, 0, sizeof(BcInstPtr));
7054 /* G.prog.nchars = G.prog.scale = 0; - already is */
7055 G.prog.len = line_len;
7057 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7058 bc_num_ten(&G.prog.ib);
7061 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7062 bc_num_ten(&G.prog.ob);
7065 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7066 bc_num_ten(&G.prog.hexb);
7067 G.prog.hexb.num[0] = 6;
7070 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7071 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7074 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7075 bc_num_zero(&G.prog.last);
7077 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7078 bc_num_zero(&G.prog.zero);
7080 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7081 bc_num_one(&G.prog.one);
7083 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7084 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7086 bc_program_addFunc(xstrdup("(main)"), &idx);
7087 bc_program_addFunc(xstrdup("(read)"), &idx);
7089 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7090 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7092 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7093 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7095 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7096 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7097 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7098 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7099 bc_vec_push(&G.prog.stack, &ip);
7102 static void bc_vm_init(const char *env_len)
7104 size_t len = bc_vm_envLen(env_len);
7106 bc_vec_init(&G.files, sizeof(char *), NULL);
7112 bc_program_init(len);
7114 bc_parse_init(&G.prs, BC_PROG_MAIN);
7116 dc_parse_init(&G.prs, BC_PROG_MAIN);
7120 static BcStatus bc_vm_run(int argc, char *argv[],
7121 const char *env_len)
7125 bc_vm_init(env_len);
7126 bc_args(argc, argv);
7128 G.ttyin = isatty(0);
7131 #if ENABLE_FEATURE_BC_SIGNALS
7132 // With SA_RESTART, most system calls will restart
7133 // (IOW: they won't fail with EINTR).
7134 // In particular, this means ^C won't cause
7135 // stdout to get into "error state" if SIGINT hits
7136 // within write() syscall.
7137 // The downside is that ^C while line input is taken
7138 // will only be handled after [Enter] since read()
7139 // from stdin is not interrupted by ^C either,
7140 // it restarts, thus fgetc() does not return on ^C.
7141 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7143 // Without SA_RESTART, this exhibits a bug:
7144 // "while (1) print 1" and try ^C-ing it.
7145 // Intermittently, instead of returning to input line,
7146 // you'll get "output error: Interrupted system call"
7148 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7150 if (!(option_mask32 & BC_FLAG_Q))
7155 #if ENABLE_FEATURE_CLEAN_UP
7162 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7163 int bc_main(int argc, char **argv)
7166 G.sbgn = G.send = '"';
7168 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7173 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7174 int dc_main(int argc, char **argv)
7180 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");