1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //See www.gnu.org/software/bc/manual/bc.html
118 //usage:#define bc_trivial_usage
119 //usage: "[-sqli] FILE..."
121 //usage:#define bc_full_usage "\n"
122 //usage: "\nArbitrary precision calculator"
124 //usage: "\n -i Interactive"
125 //usage: "\n -l Load standard math library"
126 //usage: "\n -s Be POSIX compatible"
127 //usage: "\n -q Quiet"
128 //usage: "\n -w Warn if extensions are used"
129 ///////: "\n -v Version"
131 //usage:#define bc_example_usage
132 //usage: "3 + 4.129\n"
133 //usage: "1903 - 2893\n"
134 //usage: "-129 * 213.28935\n"
135 //usage: "12 / -1932\n"
137 //usage: "34 ^ 189\n"
138 //usage: "scale = 13\n"
139 //usage: "ibase = 2\n"
140 //usage: "obase = A\n"
142 //usage:#define dc_trivial_usage
143 //usage: "EXPRESSION..."
145 //usage:#define dc_full_usage "\n\n"
146 //usage: "Tiny RPN calculator. Operations:\n"
147 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148 //usage: "modular exponentiation,\n"
149 //usage: "p - print top of the stack (without popping),\n"
150 //usage: "f - print entire stack,\n"
151 //usage: "k - pop the value and set the precision.\n"
152 //usage: "i - pop the value and set input radix.\n"
153 //usage: "o - pop the value and set output radix.\n"
154 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
156 //usage:#define dc_example_usage
157 //usage: "$ dc 2 2 + p\n"
159 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
161 //usage: "$ dc 0 1 and p\n"
163 //usage: "$ dc 0 1 or p\n"
165 //usage: "$ echo 72 9 div 8 mul p | dc\n"
170 typedef enum BcStatus {
171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
176 #define BC_VEC_INVALID_IDX ((size_t) -1)
177 #define BC_VEC_START_CAP (1 << 5)
179 typedef void (*BcVecFree)(void *);
181 typedef struct BcVec {
189 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
190 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
192 typedef signed char BcDig;
194 typedef struct BcNum {
202 #define BC_NUM_MIN_BASE ((unsigned long) 2)
203 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
204 #define BC_NUM_DEF_SIZE (16)
205 #define BC_NUM_PRINT_WIDTH (69)
207 #define BC_NUM_KARATSUBA_LEN (32)
209 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
210 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
211 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
212 #define BC_NUM_AREQ(a, b) \
213 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
214 #define BC_NUM_MREQ(a, b, scale) \
215 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
217 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
218 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
220 static void bc_num_init(BcNum *n, size_t req);
221 static void bc_num_expand(BcNum *n, size_t req);
222 static void bc_num_copy(BcNum *d, BcNum *s);
223 static void bc_num_free(void *num);
225 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
226 static void bc_num_ulong2num(BcNum *n, unsigned long val);
228 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
229 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
230 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
235 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
238 typedef enum BcInst {
268 BC_INST_ASSIGN_POWER,
269 BC_INST_ASSIGN_MULTIPLY,
270 BC_INST_ASSIGN_DIVIDE,
271 BC_INST_ASSIGN_MODULUS,
273 BC_INST_ASSIGN_MINUS,
319 BC_INST_PRINT_STREAM,
334 BC_INST_INVALID = -1,
339 typedef struct BcId {
344 typedef struct BcFunc {
351 typedef enum BcResultType {
356 BC_RESULT_ARRAY_ELEM,
365 // These are between to calculate ibase, obase, and last from instructions.
373 typedef union BcResultData {
379 typedef struct BcResult {
384 typedef struct BcInstPtr {
390 static void bc_array_expand(BcVec *a, size_t len);
391 static int bc_id_cmp(const void *e1, const void *e2);
393 // BC_LEX_NEG is not used in lexing; it is only for parsing.
394 typedef enum BcLexType {
422 BC_LEX_OP_ASSIGN_POWER,
423 BC_LEX_OP_ASSIGN_MULTIPLY,
424 BC_LEX_OP_ASSIGN_DIVIDE,
425 BC_LEX_OP_ASSIGN_MODULUS,
426 BC_LEX_OP_ASSIGN_PLUS,
427 BC_LEX_OP_ASSIGN_MINUS,
448 BC_LEX_KEY_1st_keyword,
449 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
456 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
457 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
459 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
462 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
500 // must match order of BC_LEX_KEY_foo etc above
502 struct BcLexKeyword {
505 #define BC_LEX_KW_ENTRY(a, b, c) \
506 { .name8 = a /*, .len = b, .posix = c*/ }
507 static const struct BcLexKeyword bc_lex_kws[20] = {
508 BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
509 BC_LEX_KW_ENTRY("break" , 5, 1), // 1
510 BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
511 BC_LEX_KW_ENTRY("define" , 6, 1), // 3
513 BC_LEX_KW_ENTRY("else" , 4, 0), // 4
514 BC_LEX_KW_ENTRY("for" , 3, 1), // 5
515 BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
516 BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
518 BC_LEX_KW_ENTRY("if" , 2, 1), // 8
519 BC_LEX_KW_ENTRY("last" , 4, 0), // 9
520 BC_LEX_KW_ENTRY("length" , 6, 1), // 10
521 BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
523 BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
524 BC_LEX_KW_ENTRY("print" , 5, 0), // 13
525 BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
526 BC_LEX_KW_ENTRY("read" , 4, 0), // 15
528 BC_LEX_KW_ENTRY("return" , 6, 1), // 16
529 BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
530 BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
531 BC_LEX_KW_ENTRY("while" , 5, 1), // 19
563 typedef BcStatus (*BcLexNext)(struct BcLex *);
565 typedef struct BcLex {
584 #define BC_PARSE_STREND ((char) UCHAR_MAX)
586 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
587 #define bc_parse_updateFunc(p, f) \
588 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
590 #define BC_PARSE_REL (1 << 0)
591 #define BC_PARSE_PRINT (1 << 1)
592 #define BC_PARSE_NOCALL (1 << 2)
593 #define BC_PARSE_NOREAD (1 << 3)
594 #define BC_PARSE_ARRAY (1 << 4)
596 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
597 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
599 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
600 #define BC_PARSE_FUNC_INNER(parse) \
601 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
603 #define BC_PARSE_FLAG_FUNC (1 << 1)
604 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
606 #define BC_PARSE_FLAG_BODY (1 << 2)
607 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
609 #define BC_PARSE_FLAG_LOOP (1 << 3)
610 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
612 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
613 #define BC_PARSE_LOOP_INNER(parse) \
614 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
616 #define BC_PARSE_FLAG_IF (1 << 5)
617 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
619 #define BC_PARSE_FLAG_ELSE (1 << 6)
620 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
622 #define BC_PARSE_FLAG_IF_END (1 << 7)
623 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
625 #define BC_PARSE_CAN_EXEC(parse) \
626 (!(BC_PARSE_TOP_FLAG(parse) & \
627 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
628 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
629 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
631 typedef struct BcOp {
636 typedef struct BcParseNext {
641 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
642 #define BC_PARSE_NEXT(a, ...) \
644 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
651 typedef BcStatus (*BcParseParse)(struct BcParse *);
653 typedef struct BcParse {
676 static BcStatus bc_lex_token(BcLex *l);
678 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
679 #define BC_PARSE_LEAF(p, rparen) \
680 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
681 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
683 // We can calculate the conversion between tokens and exprs by subtracting the
684 // position of the first operator in the lex enum and adding the position of the
685 // first in the expr enum. Note: This only works for binary operators.
686 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
688 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
694 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
696 static BcStatus dc_lex_token(BcLex *l);
698 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
702 typedef struct BcProgram {
743 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
745 #define BC_PROG_MAIN (0)
746 #define BC_PROG_READ (1)
749 #define BC_PROG_REQ_FUNCS (2)
752 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
753 #define BC_PROG_NUM(r, n) \
754 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
756 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
758 static void bc_program_addFunc(char *name, size_t *idx);
759 static void bc_program_reset(void);
761 #define BC_FLAG_X (1 << 0)
762 #define BC_FLAG_W (1 << 1)
763 #define BC_FLAG_V (1 << 2)
764 #define BC_FLAG_S (1 << 3)
765 #define BC_FLAG_Q (1 << 4)
766 #define BC_FLAG_L (1 << 5)
767 #define BC_FLAG_I (1 << 6)
769 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
770 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
772 #define BC_MAX_OBASE ((unsigned) 999)
773 #define BC_MAX_DIM ((unsigned) INT_MAX)
774 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
775 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
776 #define BC_MAX_NAME BC_MAX_STRING
777 #define BC_MAX_NUM BC_MAX_STRING
778 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
779 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
794 #define G (*ptr_to_globals)
795 #define INIT_G() do { \
796 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
798 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
799 #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
800 #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
801 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
804 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
806 static void bc_vm_info(void);
810 // This is an array that corresponds to token types. An entry is
811 // true if the token is valid in an expression, false otherwise.
812 static const bool bc_parse_exprs[] = {
813 false, false, true, true, true, true, true, true, true, true, true, true,
814 true, true, true, true, true, true, true, true, true, true, true, true,
815 true, true, true, false, false, true, true, false, false, false, false,
816 false, false, false, true, true, false, false, false, false, false, false,
817 false, true, false, true, true, true, true, false, false, true, false, true,
821 // This is an array of data for operators that correspond to token types.
822 static const BcOp bc_parse_ops[] = {
823 { 0, false }, { 0, false },
826 { 3, true }, { 3, true }, { 3, true },
827 { 4, true }, { 4, true },
828 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
830 { 7, true }, { 7, true },
831 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
832 { 5, false }, { 5, false },
835 // These identify what tokens can come after expressions in certain cases.
836 static const BcParseNext bc_parse_next_expr =
837 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
838 static const BcParseNext bc_parse_next_param =
839 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
840 static const BcParseNext bc_parse_next_print =
841 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
842 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
843 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
844 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
845 static const BcParseNext bc_parse_next_read =
846 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
850 static const BcLexType dc_lex_regs[] = {
851 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
852 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
853 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
857 static const BcLexType dc_lex_tokens[] = {
858 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
859 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
860 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
861 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
862 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
863 BC_LEX_INVALID, BC_LEX_INVALID,
864 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
865 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
867 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
868 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
869 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
870 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
871 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
872 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
873 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
874 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
875 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
876 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
877 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
878 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
879 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
880 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
881 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
885 static const BcInst dc_parse_insts[] = {
886 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
887 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
888 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
889 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
890 BC_INST_INVALID, BC_INST_INVALID,
891 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
894 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
895 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
896 BC_INST_INVALID, BC_INST_INVALID,
897 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
899 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
900 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
901 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
903 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
904 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
905 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
906 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
908 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
912 static const BcNumBinaryOp bc_program_ops[] = {
913 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
916 static const char bc_program_stdin_name[] = "<stdin>";
919 static const char *bc_lib_name = "gen/lib.bc";
921 static const char bc_lib[] = {
924 "\n" "auto b,s,n,r,d,i,p,f,v"
933 "\n" "scale=scale(x)+1"
943 "\n" "for(i=2;v!=0;++i){"
949 "\n" "while((d--)!=0)r*=r"
952 "\n" "if(n!=0)return(1/r)"
956 "\n" "auto b,s,r,p,a,q,i,v"
960 "\n" "r=(1-10^scale)/1"
971 "\n" "while(x<=0.5){"
975 "\n" "r=a=(x-1)/(x+1)"
978 "\n" "for(i=3;v!=0;i+=2){"
989 "\n" "auto b,s,r,n,a,q,i"
1002 "\n" "if(q%2!=0)x=-x"
1006 "\n" "for(i=3;a!=0;i+=2){"
1007 "\n" "a*=q/(i*(i-1))"
1012 "\n" "if(n!=0)return(-r/1)"
1021 "\n" "x=s(2*a(1)+x)"
1027 "\n" "auto b,s,r,n,a,m,t,f,i,u"
1036 "\n" "if(scale<65){"
1037 "\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
1041 "\n" "if(scale<65){"
1042 "\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
1053 "\n" "x=(x-.2)/(1+.2*x)"
1058 "\n" "for(i=3;t!=0;i+=2){"
1065 "\n" "return((m*a+r)/n)"
1067 "\n" "define j(n,x){"
1068 "\n" "auto b,s,o,a,i,v,f"
1076 "\n" "if(n%2==1)o=1"
1079 "\n" "for(i=2;i<=n;++i)a*=i"
1081 "\n" "a=(x^n)/2^n/a"
1084 "\n" "scale=scale+length(a)-scale(a)"
1085 "\n" "for(i=1;v!=0;++i){"
1086 "\n" "v=v*f/i/(n+i)"
1092 "\n" "return(a*r/1)"
1097 static void fflush_and_check(void)
1100 if (ferror(stdout) || ferror(stderr))
1101 bb_perror_msg_and_die("output error");
1104 static void quit(void) NORETURN;
1105 static void quit(void)
1108 bb_perror_msg_and_die("input error");
1113 static int bc_error(const char *fmt, ...)
1118 bb_verror_msg(fmt, p, NULL);
1122 return BC_STATUS_FAILURE;
1125 static int bc_posix_error(const char *fmt, ...)
1129 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
1130 return BC_STATUS_SUCCESS;
1133 bb_verror_msg(fmt, p, NULL);
1136 // Do we treat non-POSIX constructs as errors?
1137 if (!(option_mask32 & BC_FLAG_S))
1138 return BC_STATUS_SUCCESS; // no, it's a warning
1141 return BC_STATUS_FAILURE;
1144 static void bc_vec_grow(BcVec *v, size_t n)
1146 size_t cap = v->cap * 2;
1147 while (cap < v->len + n) cap *= 2;
1148 v->v = xrealloc(v->v, v->size * cap);
1152 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1155 v->cap = BC_VEC_START_CAP;
1158 v->v = xmalloc(esize * BC_VEC_START_CAP);
1161 static void bc_char_vec_init(BcVec *v)
1163 bc_vec_init(v, sizeof(char), NULL);
1166 static void bc_vec_expand(BcVec *v, size_t req)
1169 v->v = xrealloc(v->v, v->size * req);
1174 static void bc_vec_npop(BcVec *v, size_t n)
1179 size_t len = v->len - n;
1180 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1184 static void bc_vec_pop_all(BcVec *v)
1186 bc_vec_npop(v, v->len);
1189 static void bc_vec_push(BcVec *v, const void *data)
1191 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1192 memmove(v->v + (v->size * v->len), data, v->size);
1196 static void bc_vec_pushByte(BcVec *v, char data)
1198 bc_vec_push(v, &data);
1201 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1204 bc_vec_push(v, data);
1209 if (v->len == v->cap) bc_vec_grow(v, 1);
1211 ptr = v->v + v->size * idx;
1213 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1214 memmove(ptr, data, v->size);
1218 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1221 bc_vec_expand(v, len + 1);
1222 memcpy(v->v, str, len);
1225 bc_vec_pushByte(v, '\0');
1228 static void bc_vec_concat(BcVec *v, const char *str)
1232 if (v->len == 0) bc_vec_pushByte(v, '\0');
1234 len = v->len + strlen(str);
1236 if (v->cap < len) bc_vec_grow(v, len - v->len);
1242 static void *bc_vec_item(const BcVec *v, size_t idx)
1244 return v->v + v->size * idx;
1247 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1249 return v->v + v->size * (v->len - idx - 1);
1252 static void bc_vec_free(void *vec)
1254 BcVec *v = (BcVec *) vec;
1259 static size_t bc_map_find(const BcVec *v, const void *ptr)
1261 size_t low = 0, high = v->len;
1263 while (low < high) {
1265 size_t mid = (low + high) / 2;
1266 BcId *id = bc_vec_item(v, mid);
1267 int result = bc_id_cmp(ptr, id);
1271 else if (result < 0)
1280 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1282 size_t n = *i = bc_map_find(v, ptr);
1285 bc_vec_push(v, ptr);
1286 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1287 return 0; // "was not inserted"
1289 bc_vec_pushAt(v, ptr, n);
1290 return 1; // "was inserted"
1293 static size_t bc_map_index(const BcVec *v, const void *ptr)
1295 size_t i = bc_map_find(v, ptr);
1296 if (i >= v->len) return BC_VEC_INVALID_IDX;
1297 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1300 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1309 bc_vec_pop_all(vec);
1312 #if ENABLE_FEATURE_BC_SIGNALS
1313 if (bb_got_signal) { // ^C was pressed
1315 bb_got_signal = 0; // resets G_interrupt to zero
1317 ? "\ninterrupt (type \"quit\" to exit)\n"
1318 : "\ninterrupt (type \"q\" to exit)\n"
1322 if (G.ttyin && !G_posix)
1323 fputs(prompt, stderr);
1325 #if ENABLE_FEATURE_BC_SIGNALS
1331 #if ENABLE_FEATURE_BC_SIGNALS
1332 // Both conditions appear simultaneously, check both just in case
1333 if (errno == EINTR || bb_got_signal) {
1340 quit(); // this emits error message
1342 // Note: EOF does not append '\n', therefore:
1343 // printf 'print 123\n' | bc - works
1344 // printf 'print 123' | bc - fails (syntax error)
1348 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1351 // Bad chars on this line, ignore entire line
1352 bc_error("illegal character 0x%02x", i);
1356 bc_vec_push(vec, &c);
1357 } while (i != '\n');
1358 } while (bad_chars);
1360 bc_vec_pushByte(vec, '\0');
1362 return BC_STATUS_SUCCESS;
1365 static char* bc_read_file(const char *path)
1368 size_t size = ((size_t) -1);
1371 buf = xmalloc_open_read_close(path, &size);
1373 for (i = 0; i < size; ++i) {
1375 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1387 static void bc_args(int argc, char **argv)
1393 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1394 opts = getopt32long(argv, "xwvsqli",
1395 "extended-register\0" No_argument "x"
1396 "warn\0" No_argument "w"
1397 "version\0" No_argument "v"
1398 "standard\0" No_argument "s"
1399 "quiet\0" No_argument "q"
1400 "mathlib\0" No_argument "l"
1401 "interactive\0" No_argument "i"
1404 opts = getopt32(argv, "xwvsqli");
1406 if (getenv("POSIXLY_CORRECT"))
1407 option_mask32 |= BC_FLAG_S;
1409 if (opts & BC_FLAG_V) bc_vm_info();
1410 // should not be necessary, getopt32() handles this??
1411 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1413 for (i = optind; i < argc; ++i)
1414 bc_vec_push(&G.files, argv + i);
1417 static void bc_num_setToZero(BcNum *n, size_t scale)
1424 static void bc_num_zero(BcNum *n)
1426 bc_num_setToZero(n, 0);
1429 static void bc_num_one(BcNum *n)
1431 bc_num_setToZero(n, 0);
1436 static void bc_num_ten(BcNum *n)
1438 bc_num_setToZero(n, 0);
1444 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1448 for (i = 0; i < len; ++i) {
1449 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1456 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1460 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1461 return BC_NUM_NEG(i + 1, c < 0);
1464 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1466 size_t i, min, a_int, b_int, diff;
1467 BcDig *max_num, *min_num;
1468 bool a_max, neg = false;
1471 if (a == b) return 0;
1472 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1473 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1483 a_int = BC_NUM_INT(a);
1484 b_int = BC_NUM_INT(b);
1486 a_max = (a->rdx > b->rdx);
1488 if (a_int != 0) return (ssize_t) a_int;
1492 diff = a->rdx - b->rdx;
1493 max_num = a->num + diff;
1498 diff = b->rdx - a->rdx;
1499 max_num = b->num + diff;
1503 cmp = bc_num_compare(max_num, min_num, b_int + min);
1504 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1506 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1507 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1513 static void bc_num_truncate(BcNum *n, size_t places)
1515 if (places == 0) return;
1521 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1525 static void bc_num_extend(BcNum *n, size_t places)
1527 size_t len = n->len + places;
1531 if (n->cap < len) bc_num_expand(n, len);
1533 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1534 memset(n->num, 0, sizeof(BcDig) * places);
1541 static void bc_num_clean(BcNum *n)
1543 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1546 else if (n->len < n->rdx)
1550 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1553 bc_num_extend(n, scale - n->rdx);
1555 bc_num_truncate(n, n->rdx - scale);
1558 if (n->len != 0) n->neg = !neg1 != !neg2;
1561 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1566 b->len = n->len - idx;
1568 a->rdx = b->rdx = 0;
1570 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1571 memcpy(a->num, n->num, idx * sizeof(BcDig));
1582 static BcStatus bc_num_shift(BcNum *n, size_t places)
1584 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1585 if (places + n->len > BC_MAX_NUM)
1586 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1588 if (n->rdx >= places)
1591 bc_num_extend(n, places - n->rdx);
1597 return BC_STATUS_SUCCESS;
1600 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1609 return bc_num_div(&one, a, b, scale);
1612 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1614 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1615 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1618 // Because this function doesn't need to use scale (per the bc spec),
1619 // I am hijacking it to say whether it's doing an add or a subtract.
1623 if (sub && c->len) c->neg = !c->neg;
1624 return BC_STATUS_SUCCESS;
1626 else if (b->len == 0) {
1628 return BC_STATUS_SUCCESS;
1632 c->rdx = BC_MAX(a->rdx, b->rdx);
1633 min_rdx = BC_MIN(a->rdx, b->rdx);
1636 if (a->rdx > b->rdx) {
1637 diff = a->rdx - b->rdx;
1639 ptr_a = a->num + diff;
1643 diff = b->rdx - a->rdx;
1646 ptr_b = b->num + diff;
1649 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1652 a_int = BC_NUM_INT(a);
1653 b_int = BC_NUM_INT(b);
1655 if (a_int > b_int) {
1666 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1667 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1669 ptr_c[i] = (BcDig)(in % 10);
1672 for (; i < max + min_rdx; ++i, ++c->len) {
1673 in = ((int) ptr[i]) + carry;
1675 ptr_c[i] = (BcDig)(in % 10);
1678 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1680 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1683 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1686 BcNum *minuend, *subtrahend;
1688 bool aneg, bneg, neg;
1690 // Because this function doesn't need to use scale (per the bc spec),
1691 // I am hijacking it to say whether it's doing an add or a subtract.
1695 if (sub && c->len) c->neg = !c->neg;
1696 return BC_STATUS_SUCCESS;
1698 else if (b->len == 0) {
1700 return BC_STATUS_SUCCESS;
1705 a->neg = b->neg = false;
1707 cmp = bc_num_cmp(a, b);
1713 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1714 return BC_STATUS_SUCCESS;
1723 if (sub) neg = !neg;
1728 bc_num_copy(c, minuend);
1731 if (c->rdx < subtrahend->rdx) {
1732 bc_num_extend(c, subtrahend->rdx - c->rdx);
1736 start = c->rdx - subtrahend->rdx;
1738 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1742 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1745 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1750 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1751 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1752 bool aone = BC_NUM_ONE(a);
1754 if (a->len == 0 || b->len == 0) {
1756 return BC_STATUS_SUCCESS;
1758 else if (aone || BC_NUM_ONE(b)) {
1759 bc_num_copy(c, aone ? b : a);
1760 return BC_STATUS_SUCCESS;
1763 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1764 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1766 bc_num_expand(c, a->len + b->len + 1);
1768 memset(c->num, 0, sizeof(BcDig) * c->cap);
1769 c->len = carry = len = 0;
1771 for (i = 0; i < b->len; ++i) {
1773 for (j = 0; j < a->len; ++j) {
1774 int in = (int) c->num[i + j];
1775 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1777 c->num[i + j] = (BcDig)(in % 10);
1780 c->num[i + j] += (BcDig) carry;
1781 len = BC_MAX(len, i + j + !!carry);
1787 return BC_STATUS_SUCCESS;
1790 bc_num_init(&l1, max);
1791 bc_num_init(&h1, max);
1792 bc_num_init(&l2, max);
1793 bc_num_init(&h2, max);
1794 bc_num_init(&m1, max);
1795 bc_num_init(&m2, max);
1796 bc_num_init(&z0, max);
1797 bc_num_init(&z1, max);
1798 bc_num_init(&z2, max);
1799 bc_num_init(&temp, max + max);
1801 bc_num_split(a, max2, &l1, &h1);
1802 bc_num_split(b, max2, &l2, &h2);
1804 s = bc_num_add(&h1, &l1, &m1, 0);
1806 s = bc_num_add(&h2, &l2, &m2, 0);
1809 s = bc_num_k(&h1, &h2, &z0);
1811 s = bc_num_k(&m1, &m2, &z1);
1813 s = bc_num_k(&l1, &l2, &z2);
1816 s = bc_num_sub(&z1, &z0, &temp, 0);
1818 s = bc_num_sub(&temp, &z2, &z1, 0);
1821 s = bc_num_shift(&z0, max2 * 2);
1823 s = bc_num_shift(&z1, max2);
1825 s = bc_num_add(&z0, &z1, &temp, 0);
1827 s = bc_num_add(&temp, &z2, c, 0);
1843 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1847 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1849 scale = BC_MAX(scale, a->rdx);
1850 scale = BC_MAX(scale, b->rdx);
1851 scale = BC_MIN(a->rdx + b->rdx, scale);
1852 maxrdx = BC_MAX(maxrdx, scale);
1854 bc_num_init(&cpa, a->len);
1855 bc_num_init(&cpb, b->len);
1857 bc_num_copy(&cpa, a);
1858 bc_num_copy(&cpb, b);
1859 cpa.neg = cpb.neg = false;
1861 s = bc_num_shift(&cpa, maxrdx);
1863 s = bc_num_shift(&cpb, maxrdx);
1865 s = bc_num_k(&cpa, &cpb, c);
1869 bc_num_expand(c, c->len + maxrdx);
1871 if (c->len < maxrdx) {
1872 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1877 bc_num_retireMul(c, scale, a->neg, b->neg);
1885 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1887 BcStatus s = BC_STATUS_SUCCESS;
1894 return bc_error("divide by zero");
1895 else if (a->len == 0) {
1896 bc_num_setToZero(c, scale);
1897 return BC_STATUS_SUCCESS;
1899 else if (BC_NUM_ONE(b)) {
1901 bc_num_retireMul(c, scale, a->neg, b->neg);
1902 return BC_STATUS_SUCCESS;
1905 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1906 bc_num_copy(&cp, a);
1910 bc_num_expand(&cp, len + 2);
1911 bc_num_extend(&cp, len - cp.len);
1914 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1916 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1918 if (b->rdx == b->len) {
1919 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1923 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1925 // We want an extra zero in front to make things simpler.
1926 cp.num[cp.len++] = 0;
1929 bc_num_expand(c, cp.len);
1932 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1937 for (i = end - 1; !s && i < end; --i) {
1939 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1940 bc_num_subArrays(n, p, len);
1944 bc_num_retireMul(c, scale, a->neg, b->neg);
1947 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1950 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1951 BcNum *restrict d, size_t scale, size_t ts)
1958 return bc_error("divide by zero");
1961 bc_num_setToZero(d, ts);
1962 return BC_STATUS_SUCCESS;
1965 bc_num_init(&temp, d->cap);
1966 bc_num_d(a, b, c, scale);
1968 if (scale != 0) scale = ts;
1970 s = bc_num_m(c, b, &temp, scale);
1972 s = bc_num_sub(a, &temp, d, scale);
1975 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1978 bc_num_retireMul(d, ts, a->neg, b->neg);
1986 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1990 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1992 bc_num_init(&c1, len);
1993 s = bc_num_r(a, b, &c1, c, scale, ts);
1999 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2001 BcStatus s = BC_STATUS_SUCCESS;
2004 size_t i, powrdx, resrdx;
2007 if (b->rdx) return bc_error("non integer number");
2011 return BC_STATUS_SUCCESS;
2013 else if (a->len == 0) {
2014 bc_num_setToZero(c, scale);
2015 return BC_STATUS_SUCCESS;
2017 else if (BC_NUM_ONE(b)) {
2021 s = bc_num_inv(a, c, scale);
2028 s = bc_num_ulong(b, &pow);
2031 bc_num_init(©, a->len);
2032 bc_num_copy(©, a);
2034 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2038 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2040 s = bc_num_mul(©, ©, ©, powrdx);
2044 bc_num_copy(c, ©);
2046 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2049 s = bc_num_mul(©, ©, ©, powrdx);
2054 s = bc_num_mul(c, ©, c, resrdx);
2060 s = bc_num_inv(c, c, scale);
2064 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2066 // We can't use bc_num_clean() here.
2067 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2068 if (zero) bc_num_setToZero(c, scale);
2075 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2076 BcNumBinaryOp op, size_t req)
2079 BcNum num2, *ptr_a, *ptr_b;
2084 memcpy(ptr_a, c, sizeof(BcNum));
2093 memcpy(ptr_b, c, sizeof(BcNum));
2101 bc_num_init(c, req);
2103 bc_num_expand(c, req);
2105 s = op(ptr_a, ptr_b, c, scale);
2107 if (init) bc_num_free(&num2);
2112 static bool bc_num_strValid(const char *val, size_t base)
2115 bool small, radix = false;
2116 size_t i, len = strlen(val);
2118 if (!len) return true;
2121 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2123 for (i = 0; i < len; ++i) {
2129 if (radix) return false;
2135 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2142 static void bc_num_parseDecimal(BcNum *n, const char *val)
2148 for (i = 0; val[i] == '0'; ++i);
2155 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2156 bc_num_expand(n, len);
2159 ptr = strchr(val, '.');
2163 n->rdx = (size_t)((val + len) - (ptr + 1));
2166 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2167 n->num[n->len] = val[i] - '0';
2171 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2174 BcNum temp, mult, result;
2178 size_t i, digits, len = strlen(val);
2182 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2185 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2186 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2188 for (i = 0; i < len; ++i) {
2191 if (c == '.') break;
2193 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2195 s = bc_num_mul(n, base, &mult, 0);
2196 if (s) goto int_err;
2197 bc_num_ulong2num(&temp, v);
2198 s = bc_num_add(&mult, &temp, n, 0);
2199 if (s) goto int_err;
2204 if (c == 0) goto int_err;
2207 bc_num_init(&result, base->len);
2208 bc_num_zero(&result);
2211 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2216 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2218 s = bc_num_mul(&result, base, &result, 0);
2220 bc_num_ulong2num(&temp, v);
2221 s = bc_num_add(&result, &temp, &result, 0);
2223 s = bc_num_mul(&mult, base, &mult, 0);
2227 s = bc_num_div(&result, &mult, &result, digits);
2229 s = bc_num_add(n, &result, n, digits);
2233 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2239 bc_num_free(&result);
2245 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2247 if (*nchars == line_len - 1) {
2255 static void bc_num_printChar(size_t num, size_t width, bool radix,
2256 size_t *nchars, size_t line_len)
2258 (void) radix, (void) line_len;
2259 bb_putchar((char) num);
2260 *nchars = *nchars + width;
2264 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2265 size_t *nchars, size_t line_len)
2269 bc_num_printNewline(nchars, line_len);
2270 bb_putchar(radix ? '.' : ' ');
2273 bc_num_printNewline(nchars, line_len);
2274 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2277 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2279 bc_num_printNewline(nchars, line_len);
2282 bb_putchar(((char) dig) + '0');
2286 static void bc_num_printHex(size_t num, size_t width, bool radix,
2287 size_t *nchars, size_t line_len)
2290 bc_num_printNewline(nchars, line_len);
2295 bc_num_printNewline(nchars, line_len);
2296 bb_putchar(bb_hexdigits_upcase[num]);
2297 *nchars = *nchars + width;
2300 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2302 size_t i, rdx = n->rdx - 1;
2304 if (n->neg) bb_putchar('-');
2305 (*nchars) += n->neg;
2307 for (i = n->len - 1; i < n->len; --i)
2308 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2311 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2312 size_t *nchars, size_t len, BcNumDigitOp print)
2316 BcNum intp, fracp, digit, frac_len;
2317 unsigned long dig, *ptr;
2322 print(0, width, false, nchars, len);
2323 return BC_STATUS_SUCCESS;
2326 bc_vec_init(&stack, sizeof(long), NULL);
2327 bc_num_init(&intp, n->len);
2328 bc_num_init(&fracp, n->rdx);
2329 bc_num_init(&digit, width);
2330 bc_num_init(&frac_len, BC_NUM_INT(n));
2331 bc_num_copy(&intp, n);
2332 bc_num_one(&frac_len);
2334 bc_num_truncate(&intp, intp.rdx);
2335 s = bc_num_sub(n, &intp, &fracp, 0);
2338 while (intp.len != 0) {
2339 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2341 s = bc_num_ulong(&digit, &dig);
2343 bc_vec_push(&stack, &dig);
2346 for (i = 0; i < stack.len; ++i) {
2347 ptr = bc_vec_item_rev(&stack, i);
2348 print(*ptr, width, false, nchars, len);
2351 if (!n->rdx) goto err;
2353 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2354 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2356 s = bc_num_ulong(&fracp, &dig);
2358 bc_num_ulong2num(&intp, dig);
2359 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2361 print(dig, width, radix, nchars, len);
2362 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2367 bc_num_free(&frac_len);
2368 bc_num_free(&digit);
2369 bc_num_free(&fracp);
2371 bc_vec_free(&stack);
2375 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2376 size_t *nchars, size_t line_len)
2383 if (neg) bb_putchar('-');
2388 if (base_t <= BC_NUM_MAX_IBASE) {
2390 print = bc_num_printHex;
2393 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2394 print = bc_num_printDigits;
2397 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2404 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2406 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2410 static void bc_num_init(BcNum *n, size_t req)
2412 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2413 memset(n, 0, sizeof(BcNum));
2414 n->num = xmalloc(req);
2418 static void bc_num_expand(BcNum *n, size_t req)
2420 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2422 n->num = xrealloc(n->num, req);
2427 static void bc_num_free(void *num)
2429 free(((BcNum *) num)->num);
2432 static void bc_num_copy(BcNum *d, BcNum *s)
2435 bc_num_expand(d, s->cap);
2439 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2443 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2446 if (!bc_num_strValid(val, base_t))
2447 return bc_error("bad number string");
2450 bc_num_parseDecimal(n, val);
2452 bc_num_parseBase(n, val, base);
2454 return BC_STATUS_SUCCESS;
2457 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2458 size_t *nchars, size_t line_len)
2460 BcStatus s = BC_STATUS_SUCCESS;
2462 bc_num_printNewline(nchars, line_len);
2468 else if (base_t == 10)
2469 bc_num_printDecimal(n, nchars, line_len);
2471 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2481 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2486 if (n->neg) return bc_error("negative number");
2488 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2490 unsigned long prev = *result, powprev = pow;
2492 *result += ((unsigned long) n->num[i]) * pow;
2495 if (*result < prev || pow < powprev)
2496 return bc_error("overflow");
2499 return BC_STATUS_SUCCESS;
2502 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2510 if (val == 0) return;
2512 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2513 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2516 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2518 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2520 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2523 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2525 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2527 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2530 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2532 size_t req = BC_NUM_MREQ(a, b, scale);
2533 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2536 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2538 size_t req = BC_NUM_MREQ(a, b, scale);
2539 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2542 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2544 size_t req = BC_NUM_MREQ(a, b, scale);
2545 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2548 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2550 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2553 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2556 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2557 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2558 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2560 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2561 bc_num_expand(b, req);
2564 bc_num_setToZero(b, scale);
2565 return BC_STATUS_SUCCESS;
2568 return bc_error("negative number");
2569 else if (BC_NUM_ONE(a)) {
2571 bc_num_extend(b, scale);
2572 return BC_STATUS_SUCCESS;
2575 scale = BC_MAX(scale, a->rdx) + 1;
2576 len = a->len + scale;
2578 bc_num_init(&num1, len);
2579 bc_num_init(&num2, len);
2580 bc_num_init(&half, BC_NUM_DEF_SIZE);
2586 bc_num_init(&f, len);
2587 bc_num_init(&fprime, len);
2593 pow = BC_NUM_INT(a);
2602 pow -= 2 - (pow & 1);
2604 bc_num_extend(x0, pow);
2606 // Make sure to move the radix back.
2610 x0->rdx = digs = digs1 = 0;
2612 len = BC_NUM_INT(x0) + resrdx - 1;
2614 while (cmp != 0 || digs < len) {
2616 s = bc_num_div(a, x0, &f, resrdx);
2618 s = bc_num_add(x0, &f, &fprime, resrdx);
2620 s = bc_num_mul(&fprime, &half, x1, resrdx);
2623 cmp = bc_num_cmp(x1, x0);
2624 digs = x1->len - (unsigned long long) llabs(cmp);
2626 if (cmp == cmp2 && digs == digs1)
2631 resrdx += times > 4;
2644 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2647 bc_num_free(&fprime);
2655 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2661 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2664 memcpy(&num2, c, sizeof(BcNum));
2666 bc_num_init(c, len);
2671 bc_num_expand(c, len);
2674 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2676 if (init) bc_num_free(&num2);
2682 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2685 BcNum base, exp, two, temp;
2688 return bc_error("divide by zero");
2689 if (a->rdx || b->rdx || c->rdx)
2690 return bc_error("non integer number");
2692 return bc_error("negative number");
2694 bc_num_expand(d, c->len);
2695 bc_num_init(&base, c->len);
2696 bc_num_init(&exp, b->len);
2697 bc_num_init(&two, BC_NUM_DEF_SIZE);
2698 bc_num_init(&temp, b->len);
2704 s = bc_num_rem(a, c, &base, 0);
2706 bc_num_copy(&exp, b);
2708 while (exp.len != 0) {
2710 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2713 if (BC_NUM_ONE(&temp)) {
2714 s = bc_num_mul(d, &base, &temp, 0);
2716 s = bc_num_rem(&temp, c, d, 0);
2720 s = bc_num_mul(&base, &base, &temp, 0);
2722 s = bc_num_rem(&temp, c, &base, 0);
2735 static int bc_id_cmp(const void *e1, const void *e2)
2737 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2740 static void bc_id_free(void *id)
2742 free(((BcId *) id)->name);
2745 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2750 for (i = 0; i < f->autos.len; ++i) {
2751 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2752 return bc_error("function parameter or auto var has the same name as another");
2758 bc_vec_push(&f->autos, &a);
2760 return BC_STATUS_SUCCESS;
2763 static void bc_func_init(BcFunc *f)
2765 bc_char_vec_init(&f->code);
2766 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2767 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2771 static void bc_func_free(void *func)
2773 BcFunc *f = (BcFunc *) func;
2774 bc_vec_free(&f->code);
2775 bc_vec_free(&f->autos);
2776 bc_vec_free(&f->labels);
2779 static void bc_array_init(BcVec *a, bool nums)
2782 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2784 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2785 bc_array_expand(a, 1);
2788 static void bc_array_copy(BcVec *d, const BcVec *s)
2793 bc_vec_expand(d, s->cap);
2796 for (i = 0; i < s->len; ++i) {
2797 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2798 bc_num_init(dnum, snum->len);
2799 bc_num_copy(dnum, snum);
2803 static void bc_array_expand(BcVec *a, size_t len)
2807 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2808 while (len > a->len) {
2809 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2810 bc_vec_push(a, &data.n);
2814 while (len > a->len) {
2815 bc_array_init(&data.v, true);
2816 bc_vec_push(a, &data.v);
2821 static void bc_string_free(void *string)
2823 free(*((char **) string));
2827 static void bc_result_copy(BcResult *d, BcResult *src)
2833 case BC_RESULT_TEMP:
2834 case BC_RESULT_IBASE:
2835 case BC_RESULT_SCALE:
2836 case BC_RESULT_OBASE:
2838 bc_num_init(&d->d.n, src->d.n.len);
2839 bc_num_copy(&d->d.n, &src->d.n);
2844 case BC_RESULT_ARRAY:
2845 case BC_RESULT_ARRAY_ELEM:
2847 d->d.id.name = xstrdup(src->d.id.name);
2851 case BC_RESULT_CONSTANT:
2852 case BC_RESULT_LAST:
2856 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2863 static void bc_result_free(void *result)
2865 BcResult *r = (BcResult *) result;
2869 case BC_RESULT_TEMP:
2870 case BC_RESULT_IBASE:
2871 case BC_RESULT_SCALE:
2872 case BC_RESULT_OBASE:
2874 bc_num_free(&r->d.n);
2879 case BC_RESULT_ARRAY:
2880 case BC_RESULT_ARRAY_ELEM:
2894 static void bc_lex_lineComment(BcLex *l)
2896 l->t.t = BC_LEX_WHITESPACE;
2897 while (l->i < l->len && l->buf[l->i++] != '\n');
2901 static void bc_lex_whitespace(BcLex *l)
2904 l->t.t = BC_LEX_WHITESPACE;
2905 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2908 static BcStatus bc_lex_number(BcLex *l, char start)
2910 const char *buf = l->buf + l->i;
2911 size_t len, hits = 0, bslashes = 0, i = 0, j;
2913 bool last_pt, pt = start == '.';
2916 l->t.t = BC_LEX_NUMBER;
2918 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2919 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2933 len = i + !last_pt - bslashes * 2;
2934 if (len > BC_MAX_NUM)
2935 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2937 bc_vec_pop_all(&l->t.v);
2938 bc_vec_expand(&l->t.v, len + 1);
2939 bc_vec_push(&l->t.v, &start);
2941 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2945 // If we have hit a backslash, skip it. We don't have
2946 // to check for a newline because it's guaranteed.
2947 if (hits < bslashes && c == '\\') {
2953 bc_vec_push(&l->t.v, &c);
2956 bc_vec_pushByte(&l->t.v, '\0');
2959 return BC_STATUS_SUCCESS;
2962 static BcStatus bc_lex_name(BcLex *l)
2965 const char *buf = l->buf + l->i - 1;
2968 l->t.t = BC_LEX_NAME;
2970 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2972 if (i > BC_MAX_STRING)
2973 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2974 bc_vec_string(&l->t.v, i, buf);
2976 // Increment the index. We minus 1 because it has already been incremented.
2979 return BC_STATUS_SUCCESS;
2982 static void bc_lex_init(BcLex *l, BcLexNext next)
2985 bc_char_vec_init(&l->t.v);
2988 static void bc_lex_free(BcLex *l)
2990 bc_vec_free(&l->t.v);
2993 static void bc_lex_file(BcLex *l, const char *file)
3000 static BcStatus bc_lex_next(BcLex *l)
3005 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
3007 l->line += l->newline;
3008 l->t.t = BC_LEX_EOF;
3010 l->newline = (l->i == l->len);
3011 if (l->newline) return BC_STATUS_SUCCESS;
3013 // Loop until failure or we don't have whitespace. This
3014 // is so the parser doesn't get inundated with whitespace.
3017 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3022 static BcStatus bc_lex_text(BcLex *l, const char *text)
3026 l->len = strlen(text);
3027 l->t.t = l->t.last = BC_LEX_INVALID;
3028 return bc_lex_next(l);
3032 static BcStatus bc_lex_identifier(BcLex *l)
3036 const char *buf = l->buf + l->i - 1;
3038 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
3039 const char *keyword8 = bc_lex_kws[i].name8;
3041 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
3043 if (j == 8) goto match;
3045 if (keyword8[j] != '\0')
3048 // buf starts with keyword bc_lex_kws[i]
3049 l->t.t = BC_LEX_KEY_1st_keyword + i;
3050 if ((1 << i) & POSIX_KWORD_MASK) {
3051 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name8
3055 // We minus 1 because the index has already been incremented.
3057 return BC_STATUS_SUCCESS;
3064 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
3069 static BcStatus bc_lex_string(BcLex *l)
3071 size_t len, nls = 0, i = l->i;
3074 l->t.t = BC_LEX_STR;
3076 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3080 return bc_error("string end could not be found");
3084 if (len > BC_MAX_STRING)
3085 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3086 bc_vec_string(&l->t.v, len, l->buf + l->i);
3091 return BC_STATUS_SUCCESS;
3094 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3096 if (l->buf[l->i] == '=') {
3104 static BcStatus bc_lex_comment(BcLex *l)
3107 const char *buf = l->buf;
3109 l->t.t = BC_LEX_WHITESPACE;
3122 return bc_error("comment end could not be found");
3131 return BC_STATUS_SUCCESS;
3134 static BcStatus bc_lex_token(BcLex *l)
3136 BcStatus s = BC_STATUS_SUCCESS;
3137 char c = l->buf[l->i++], c2;
3139 // This is the workhorse of the lexer.
3146 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3156 bc_lex_whitespace(l);
3162 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3164 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3165 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
3174 s = bc_lex_string(l);
3180 s = bc_posix_error("POSIX does not allow '#' script comments");
3183 bc_lex_lineComment(l);
3190 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3199 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
3203 l->t.t = BC_LEX_OP_BOOL_AND;
3206 l->t.t = BC_LEX_INVALID;
3207 s = bc_error("bad character '%c'", '&');
3216 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3222 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3231 l->t.t = BC_LEX_OP_INC;
3234 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3240 l->t.t = BC_LEX_COMMA;
3249 l->t.t = BC_LEX_OP_DEC;
3252 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3258 if (isdigit(l->buf[l->i]))
3259 s = bc_lex_number(l, c);
3261 l->t.t = BC_LEX_KEY_LAST;
3262 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
3271 s = bc_lex_comment(l);
3273 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3294 s = bc_lex_number(l, c);
3300 l->t.t = BC_LEX_SCOLON;
3306 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3312 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3318 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3325 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3331 if (l->buf[l->i] == '\n') {
3332 l->t.t = BC_LEX_WHITESPACE;
3336 s = bc_error("bad character '%c'", c);
3342 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3373 s = bc_lex_identifier(l);
3380 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3389 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
3393 l->t.t = BC_LEX_OP_BOOL_OR;
3396 l->t.t = BC_LEX_INVALID;
3397 s = bc_error("bad character '%c'", c);
3405 l->t.t = BC_LEX_INVALID;
3406 s = bc_error("bad character '%c'", c);
3416 static BcStatus dc_lex_register(BcLex *l)
3418 BcStatus s = BC_STATUS_SUCCESS;
3420 if (isspace(l->buf[l->i - 1])) {
3421 bc_lex_whitespace(l);
3424 s = bc_error("extended register");
3429 bc_vec_pop_all(&l->t.v);
3430 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3431 bc_vec_pushByte(&l->t.v, '\0');
3432 l->t.t = BC_LEX_NAME;
3438 static BcStatus dc_lex_string(BcLex *l)
3440 size_t depth = 1, nls = 0, i = l->i;
3443 l->t.t = BC_LEX_STR;
3444 bc_vec_pop_all(&l->t.v);
3446 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3448 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3449 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3452 if (depth) bc_vec_push(&l->t.v, &c);
3457 return bc_error("string end could not be found");
3460 bc_vec_pushByte(&l->t.v, '\0');
3461 if (i - l->i > BC_MAX_STRING)
3462 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3467 return BC_STATUS_SUCCESS;
3470 static BcStatus dc_lex_token(BcLex *l)
3472 BcStatus s = BC_STATUS_SUCCESS;
3473 char c = l->buf[l->i++], c2;
3476 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3477 if (l->t.last == dc_lex_regs[i])
3478 return dc_lex_register(l);
3481 if (c >= '%' && c <= '~' &&
3482 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3487 // This is the workhorse of the lexer.
3492 l->t.t = BC_LEX_EOF;
3503 l->newline = (c == '\n');
3504 bc_lex_whitespace(l);
3513 l->t.t = BC_LEX_OP_REL_NE;
3515 l->t.t = BC_LEX_OP_REL_LE;
3517 l->t.t = BC_LEX_OP_REL_GE;
3519 return bc_error("bad character '%c'", c);
3527 bc_lex_lineComment(l);
3533 if (isdigit(l->buf[l->i]))
3534 s = bc_lex_number(l, c);
3536 s = bc_error("bad character '%c'", c);
3557 s = bc_lex_number(l, c);
3563 s = dc_lex_string(l);
3569 l->t.t = BC_LEX_INVALID;
3570 s = bc_error("bad character '%c'", c);
3579 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3581 bc_program_addFunc(name, idx);
3582 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3585 static void bc_parse_pushName(BcParse *p, char *name)
3587 size_t i = 0, len = strlen(name);
3589 for (; i < len; ++i) bc_parse_push(p, name[i]);
3590 bc_parse_push(p, BC_PARSE_STREND);
3595 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3597 unsigned char amt, i, nums[sizeof(size_t)];
3599 for (amt = 0; idx; ++amt) {
3600 nums[amt] = (char) idx;
3601 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3604 bc_parse_push(p, amt);
3605 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3608 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3610 char *num = xstrdup(p->l.t.v.v);
3611 size_t idx = G.prog.consts.len;
3613 bc_vec_push(&G.prog.consts, &num);
3615 bc_parse_push(p, BC_INST_NUM);
3616 bc_parse_pushIndex(p, idx);
3619 (*prev) = BC_INST_NUM;
3622 static BcStatus bc_parse_text(BcParse *p, const char *text)
3626 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3628 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3629 p->l.t.t = BC_LEX_INVALID;
3632 if (!BC_PARSE_CAN_EXEC(p))
3633 return bc_error("file is not executable");
3636 return bc_lex_text(&p->l, text);
3639 // Called when bc/dc_parse_parse() detects a failure,
3640 // resets parsing structures.
3641 static void bc_parse_reset(BcParse *p)
3643 if (p->fidx != BC_PROG_MAIN) {
3644 p->func->nparams = 0;
3645 bc_vec_pop_all(&p->func->code);
3646 bc_vec_pop_all(&p->func->autos);
3647 bc_vec_pop_all(&p->func->labels);
3649 bc_parse_updateFunc(p, BC_PROG_MAIN);
3653 p->l.t.t = BC_LEX_EOF;
3654 p->auto_part = (p->nbraces = 0);
3656 bc_vec_npop(&p->flags, p->flags.len - 1);
3657 bc_vec_pop_all(&p->exits);
3658 bc_vec_pop_all(&p->conds);
3659 bc_vec_pop_all(&p->ops);
3664 static void bc_parse_free(BcParse *p)
3666 bc_vec_free(&p->flags);
3667 bc_vec_free(&p->exits);
3668 bc_vec_free(&p->conds);
3669 bc_vec_free(&p->ops);
3673 static void bc_parse_create(BcParse *p, size_t func,
3674 BcParseParse parse, BcLexNext next)
3676 memset(p, 0, sizeof(BcParse));
3678 bc_lex_init(&p->l, next);
3679 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3680 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3681 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3682 bc_vec_pushByte(&p->flags, 0);
3683 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3686 // p->auto_part = p->nbraces = 0; - already is
3687 bc_parse_updateFunc(p, func);
3691 static BcStatus bc_parse_else(BcParse *p);
3692 static BcStatus bc_parse_stmt(BcParse *p);
3694 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3695 size_t *nexprs, bool next)
3697 BcStatus s = BC_STATUS_SUCCESS;
3699 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3700 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3702 while (p->ops.len > start) {
3704 t = BC_PARSE_TOP_OP(p);
3705 if (t == BC_LEX_LPAREN) break;
3707 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3708 if (l >= r && (l != r || !left)) break;
3710 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3711 bc_vec_pop(&p->ops);
3712 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3715 bc_vec_push(&p->ops, &type);
3716 if (next) s = bc_lex_next(&p->l);
3721 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3725 if (p->ops.len <= ops_bgn)
3726 return bc_error("bad expression");
3727 top = BC_PARSE_TOP_OP(p);
3729 while (top != BC_LEX_LPAREN) {
3731 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3733 bc_vec_pop(&p->ops);
3734 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3736 if (p->ops.len <= ops_bgn)
3737 return bc_error("bad expression");
3738 top = BC_PARSE_TOP_OP(p);
3741 bc_vec_pop(&p->ops);
3743 return bc_lex_next(&p->l);
3746 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3752 s = bc_lex_next(&p->l);
3755 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3757 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3758 s = bc_parse_expr(p, flags, bc_parse_next_param);
3761 comma = p->l.t.t == BC_LEX_COMMA;
3763 s = bc_lex_next(&p->l);
3768 if (comma) return bc_error("bad token");
3769 bc_parse_push(p, BC_INST_CALL);
3770 bc_parse_pushIndex(p, nparams);
3772 return BC_STATUS_SUCCESS;
3775 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3778 BcId entry, *entry_ptr;
3783 s = bc_parse_params(p, flags);
3786 if (p->l.t.t != BC_LEX_RPAREN) {
3787 s = bc_error("bad token");
3791 idx = bc_map_index(&G.prog.fn_map, &entry);
3793 if (idx == BC_VEC_INVALID_IDX) {
3794 name = xstrdup(entry.name);
3795 bc_parse_addFunc(p, name, &idx);
3796 idx = bc_map_index(&G.prog.fn_map, &entry);
3802 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3803 bc_parse_pushIndex(p, entry_ptr->idx);
3805 return bc_lex_next(&p->l);
3812 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3817 name = xstrdup(p->l.t.v.v);
3818 s = bc_lex_next(&p->l);
3821 if (p->l.t.t == BC_LEX_LBRACKET) {
3823 s = bc_lex_next(&p->l);
3826 if (p->l.t.t == BC_LEX_RBRACKET) {
3828 if (!(flags & BC_PARSE_ARRAY)) {
3829 s = bc_error("bad expression");
3833 *type = BC_INST_ARRAY;
3837 *type = BC_INST_ARRAY_ELEM;
3839 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3840 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3844 s = bc_lex_next(&p->l);
3846 bc_parse_push(p, *type);
3847 bc_parse_pushName(p, name);
3849 else if (p->l.t.t == BC_LEX_LPAREN) {
3851 if (flags & BC_PARSE_NOCALL) {
3852 s = bc_error("bad token");
3856 *type = BC_INST_CALL;
3857 s = bc_parse_call(p, name, flags);
3860 *type = BC_INST_VAR;
3861 bc_parse_push(p, BC_INST_VAR);
3862 bc_parse_pushName(p, name);
3872 static BcStatus bc_parse_read(BcParse *p)
3876 s = bc_lex_next(&p->l);
3878 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3880 s = bc_lex_next(&p->l);
3882 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3884 bc_parse_push(p, BC_INST_READ);
3886 return bc_lex_next(&p->l);
3889 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3894 s = bc_lex_next(&p->l);
3896 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3898 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3900 s = bc_lex_next(&p->l);
3903 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3906 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3908 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3909 bc_parse_push(p, *prev);
3911 return bc_lex_next(&p->l);
3914 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3918 s = bc_lex_next(&p->l);
3921 if (p->l.t.t != BC_LEX_LPAREN) {
3922 *type = BC_INST_SCALE;
3923 bc_parse_push(p, BC_INST_SCALE);
3924 return BC_STATUS_SUCCESS;
3927 *type = BC_INST_SCALE_FUNC;
3928 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3930 s = bc_lex_next(&p->l);
3933 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3935 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3936 bc_parse_push(p, BC_INST_SCALE_FUNC);
3938 return bc_lex_next(&p->l);
3941 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3942 size_t *nexprs, uint8_t flags)
3947 BcInst etype = *prev;
3949 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3950 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3951 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3953 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3954 bc_parse_push(p, inst);
3955 s = bc_lex_next(&p->l);
3959 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3962 s = bc_lex_next(&p->l);
3966 // Because we parse the next part of the expression
3967 // right here, we need to increment this.
3968 *nexprs = *nexprs + 1;
3974 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3978 case BC_LEX_KEY_IBASE:
3979 case BC_LEX_KEY_LAST:
3980 case BC_LEX_KEY_OBASE:
3982 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3983 s = bc_lex_next(&p->l);
3987 case BC_LEX_KEY_SCALE:
3989 s = bc_lex_next(&p->l);
3991 if (p->l.t.t == BC_LEX_LPAREN)
3992 s = bc_error("bad token");
3994 bc_parse_push(p, BC_INST_SCALE);
4000 s = bc_error("bad token");
4005 if (!s) bc_parse_push(p, inst);
4011 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4012 bool rparen, size_t *nexprs)
4016 BcInst etype = *prev;
4018 s = bc_lex_next(&p->l);
4021 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4022 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4025 *prev = BC_PARSE_TOKEN_INST(type);
4027 // We can just push onto the op stack because this is the largest
4028 // precedence operator that gets pushed. Inc/dec does not.
4029 if (type != BC_LEX_OP_MINUS)
4030 bc_vec_push(&p->ops, &type);
4032 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4037 static BcStatus bc_parse_string(BcParse *p, char inst)
4039 char *str = xstrdup(p->l.t.v.v);
4041 bc_parse_push(p, BC_INST_STR);
4042 bc_parse_pushIndex(p, G.prog.strs.len);
4043 bc_vec_push(&G.prog.strs, &str);
4044 bc_parse_push(p, inst);
4046 return bc_lex_next(&p->l);
4049 static BcStatus bc_parse_print(BcParse *p)
4055 s = bc_lex_next(&p->l);
4060 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4061 return bc_error("bad print statement");
4063 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4065 if (type == BC_LEX_STR)
4066 s = bc_parse_string(p, BC_INST_PRINT_POP);
4068 s = bc_parse_expr(p, 0, bc_parse_next_print);
4070 bc_parse_push(p, BC_INST_PRINT_POP);
4075 comma = p->l.t.t == BC_LEX_COMMA;
4076 if (comma) s = bc_lex_next(&p->l);
4081 if (comma) return bc_error("bad token");
4083 return bc_lex_next(&p->l);
4086 static BcStatus bc_parse_return(BcParse *p)
4092 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
4094 s = bc_lex_next(&p->l);
4098 paren = t == BC_LEX_LPAREN;
4100 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4101 bc_parse_push(p, BC_INST_RET0);
4104 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4105 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4108 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4109 bc_parse_push(p, BC_INST_RET0);
4110 s = bc_lex_next(&p->l);
4114 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4115 s = bc_posix_error("POSIX requires parentheses around return expressions");
4119 bc_parse_push(p, BC_INST_RET);
4125 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4127 BcStatus s = BC_STATUS_SUCCESS;
4129 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4130 return bc_error("bad token");
4134 if (p->l.t.t == BC_LEX_RBRACE) {
4135 if (!p->nbraces) return bc_error("bad token");
4137 s = bc_lex_next(&p->l);
4141 return bc_error("bad token");
4144 if (BC_PARSE_IF(p)) {
4148 while (p->l.t.t == BC_LEX_NLINE) {
4149 s = bc_lex_next(&p->l);
4153 bc_vec_pop(&p->flags);
4155 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4156 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4158 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4160 else if (BC_PARSE_ELSE(p)) {
4165 bc_vec_pop(&p->flags);
4167 ip = bc_vec_top(&p->exits);
4168 label = bc_vec_item(&p->func->labels, ip->idx);
4169 *label = p->func->code.len;
4171 bc_vec_pop(&p->exits);
4173 else if (BC_PARSE_FUNC_INNER(p)) {
4174 bc_parse_push(p, BC_INST_RET0);
4175 bc_parse_updateFunc(p, BC_PROG_MAIN);
4176 bc_vec_pop(&p->flags);
4180 BcInstPtr *ip = bc_vec_top(&p->exits);
4181 size_t *label = bc_vec_top(&p->conds);
4183 bc_parse_push(p, BC_INST_JUMP);
4184 bc_parse_pushIndex(p, *label);
4186 label = bc_vec_item(&p->func->labels, ip->idx);
4187 *label = p->func->code.len;
4189 bc_vec_pop(&p->flags);
4190 bc_vec_pop(&p->exits);
4191 bc_vec_pop(&p->conds);
4197 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4199 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4200 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4201 flags |= BC_PARSE_FLAG_BODY;
4202 bc_vec_push(&p->flags, &flags);
4205 static void bc_parse_noElse(BcParse *p)
4209 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4211 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4213 ip = bc_vec_top(&p->exits);
4214 label = bc_vec_item(&p->func->labels, ip->idx);
4215 *label = p->func->code.len;
4217 bc_vec_pop(&p->exits);
4220 static BcStatus bc_parse_if(BcParse *p)
4225 s = bc_lex_next(&p->l);
4227 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4229 s = bc_lex_next(&p->l);
4231 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4233 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4235 s = bc_lex_next(&p->l);
4237 bc_parse_push(p, BC_INST_JUMP_ZERO);
4239 ip.idx = p->func->labels.len;
4240 ip.func = ip.len = 0;
4242 bc_parse_pushIndex(p, ip.idx);
4243 bc_vec_push(&p->exits, &ip);
4244 bc_vec_push(&p->func->labels, &ip.idx);
4245 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4247 return BC_STATUS_SUCCESS;
4250 static BcStatus bc_parse_else(BcParse *p)
4254 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
4256 ip.idx = p->func->labels.len;
4257 ip.func = ip.len = 0;
4259 bc_parse_push(p, BC_INST_JUMP);
4260 bc_parse_pushIndex(p, ip.idx);
4264 bc_vec_push(&p->exits, &ip);
4265 bc_vec_push(&p->func->labels, &ip.idx);
4266 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4268 return bc_lex_next(&p->l);
4271 static BcStatus bc_parse_while(BcParse *p)
4276 s = bc_lex_next(&p->l);
4278 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4279 s = bc_lex_next(&p->l);
4282 ip.idx = p->func->labels.len;
4284 bc_vec_push(&p->func->labels, &p->func->code.len);
4285 bc_vec_push(&p->conds, &ip.idx);
4287 ip.idx = p->func->labels.len;
4291 bc_vec_push(&p->exits, &ip);
4292 bc_vec_push(&p->func->labels, &ip.idx);
4294 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4296 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4297 s = bc_lex_next(&p->l);
4300 bc_parse_push(p, BC_INST_JUMP_ZERO);
4301 bc_parse_pushIndex(p, ip.idx);
4302 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4304 return BC_STATUS_SUCCESS;
4307 static BcStatus bc_parse_for(BcParse *p)
4311 size_t cond_idx, exit_idx, body_idx, update_idx;
4313 s = bc_lex_next(&p->l);
4315 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4316 s = bc_lex_next(&p->l);
4319 if (p->l.t.t != BC_LEX_SCOLON)
4320 s = bc_parse_expr(p, 0, bc_parse_next_for);
4322 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
4325 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4326 s = bc_lex_next(&p->l);
4329 cond_idx = p->func->labels.len;
4330 update_idx = cond_idx + 1;
4331 body_idx = update_idx + 1;
4332 exit_idx = body_idx + 1;
4334 bc_vec_push(&p->func->labels, &p->func->code.len);
4336 if (p->l.t.t != BC_LEX_SCOLON)
4337 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4339 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
4342 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4344 s = bc_lex_next(&p->l);
4347 bc_parse_push(p, BC_INST_JUMP_ZERO);
4348 bc_parse_pushIndex(p, exit_idx);
4349 bc_parse_push(p, BC_INST_JUMP);
4350 bc_parse_pushIndex(p, body_idx);
4352 ip.idx = p->func->labels.len;
4354 bc_vec_push(&p->conds, &update_idx);
4355 bc_vec_push(&p->func->labels, &p->func->code.len);
4357 if (p->l.t.t != BC_LEX_RPAREN)
4358 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4360 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
4364 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4365 bc_parse_push(p, BC_INST_JUMP);
4366 bc_parse_pushIndex(p, cond_idx);
4367 bc_vec_push(&p->func->labels, &p->func->code.len);
4373 bc_vec_push(&p->exits, &ip);
4374 bc_vec_push(&p->func->labels, &ip.idx);
4376 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4378 return BC_STATUS_SUCCESS;
4381 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4387 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
4389 if (type == BC_LEX_KEY_BREAK) {
4391 if (p->exits.len == 0) return bc_error("bad token");
4393 i = p->exits.len - 1;
4394 ip = bc_vec_item(&p->exits, i);
4396 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4397 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
4402 i = *((size_t *) bc_vec_top(&p->conds));
4404 bc_parse_push(p, BC_INST_JUMP);
4405 bc_parse_pushIndex(p, i);
4407 s = bc_lex_next(&p->l);
4410 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4411 return bc_error("bad token");
4413 return bc_lex_next(&p->l);
4416 static BcStatus bc_parse_func(BcParse *p)
4419 bool var, comma = false;
4423 s = bc_lex_next(&p->l);
4425 if (p->l.t.t != BC_LEX_NAME)
4426 return bc_error("bad function definition");
4428 name = xstrdup(p->l.t.v.v);
4429 bc_parse_addFunc(p, name, &p->fidx);
4431 s = bc_lex_next(&p->l);
4433 if (p->l.t.t != BC_LEX_LPAREN)
4434 return bc_error("bad function definition");
4435 s = bc_lex_next(&p->l);
4438 while (p->l.t.t != BC_LEX_RPAREN) {
4440 if (p->l.t.t != BC_LEX_NAME)
4441 return bc_error("bad function definition");
4445 name = xstrdup(p->l.t.v.v);
4446 s = bc_lex_next(&p->l);
4449 var = p->l.t.t != BC_LEX_LBRACKET;
4453 s = bc_lex_next(&p->l);
4456 if (p->l.t.t != BC_LEX_RBRACKET) {
4457 s = bc_error("bad function definition");
4461 s = bc_lex_next(&p->l);
4465 comma = p->l.t.t == BC_LEX_COMMA;
4467 s = bc_lex_next(&p->l);
4471 s = bc_func_insert(p->func, name, var);
4475 if (comma) return bc_error("bad function definition");
4477 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4478 bc_parse_startBody(p, flags);
4480 s = bc_lex_next(&p->l);
4483 if (p->l.t.t != BC_LEX_LBRACE)
4484 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
4493 static BcStatus bc_parse_auto(BcParse *p)
4496 bool comma, var, one;
4499 if (!p->auto_part) return bc_error("bad token");
4500 s = bc_lex_next(&p->l);
4503 p->auto_part = comma = false;
4504 one = p->l.t.t == BC_LEX_NAME;
4506 while (p->l.t.t == BC_LEX_NAME) {
4508 name = xstrdup(p->l.t.v.v);
4509 s = bc_lex_next(&p->l);
4512 var = p->l.t.t != BC_LEX_LBRACKET;
4515 s = bc_lex_next(&p->l);
4518 if (p->l.t.t != BC_LEX_RBRACKET) {
4519 s = bc_error("bad function definition");
4523 s = bc_lex_next(&p->l);
4527 comma = p->l.t.t == BC_LEX_COMMA;
4529 s = bc_lex_next(&p->l);
4533 s = bc_func_insert(p->func, name, var);
4537 if (comma) return bc_error("bad function definition");
4538 if (!one) return bc_error("no auto variable found");
4540 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4541 return bc_error("bad token");
4543 return bc_lex_next(&p->l);
4550 static BcStatus bc_parse_body(BcParse *p, bool brace)
4552 BcStatus s = BC_STATUS_SUCCESS;
4553 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4555 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4557 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4559 if (!brace) return bc_error("bad token");
4560 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4562 if (!p->auto_part) {
4563 s = bc_parse_auto(p);
4567 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4570 s = bc_parse_stmt(p);
4571 if (!s && !brace) s = bc_parse_endBody(p, false);
4577 static BcStatus bc_parse_stmt(BcParse *p)
4579 BcStatus s = BC_STATUS_SUCCESS;
4585 return bc_lex_next(&p->l);
4588 case BC_LEX_KEY_ELSE:
4590 p->auto_part = false;
4596 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
4599 s = bc_lex_next(&p->l);
4602 return bc_parse_body(p, true);
4605 case BC_LEX_KEY_AUTO:
4607 return bc_parse_auto(p);
4612 p->auto_part = false;
4614 if (BC_PARSE_IF_END(p)) {
4616 return BC_STATUS_SUCCESS;
4618 else if (BC_PARSE_BODY(p))
4619 return bc_parse_body(p, false);
4629 case BC_LEX_OP_MINUS:
4630 case BC_LEX_OP_BOOL_NOT:
4634 case BC_LEX_KEY_IBASE:
4635 case BC_LEX_KEY_LAST:
4636 case BC_LEX_KEY_LENGTH:
4637 case BC_LEX_KEY_OBASE:
4638 case BC_LEX_KEY_READ:
4639 case BC_LEX_KEY_SCALE:
4640 case BC_LEX_KEY_SQRT:
4642 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4646 case BC_LEX_KEY_ELSE:
4648 s = bc_parse_else(p);
4654 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4660 s = bc_parse_endBody(p, true);
4666 s = bc_parse_string(p, BC_INST_PRINT_STR);
4670 case BC_LEX_KEY_BREAK:
4671 case BC_LEX_KEY_CONTINUE:
4673 s = bc_parse_loopExit(p, p->l.t.t);
4677 case BC_LEX_KEY_FOR:
4679 s = bc_parse_for(p);
4683 case BC_LEX_KEY_HALT:
4685 bc_parse_push(p, BC_INST_HALT);
4686 s = bc_lex_next(&p->l);
4696 case BC_LEX_KEY_LIMITS:
4698 // "limits" is a compile-time command,
4699 // the output is produced at _parse time_.
4700 s = bc_lex_next(&p->l);
4702 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4703 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4704 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4705 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4706 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4707 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4708 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4709 printf("Number of vars = %lu\n", BC_MAX_VARS);
4713 case BC_LEX_KEY_PRINT:
4715 s = bc_parse_print(p);
4719 case BC_LEX_KEY_QUIT:
4721 // "quit" is a compile-time command. For example,
4722 // "if (0 == 1) quit" terminates when parsing the statement,
4723 // not when it is executed
4727 case BC_LEX_KEY_RETURN:
4729 s = bc_parse_return(p);
4733 case BC_LEX_KEY_WHILE:
4735 s = bc_parse_while(p);
4741 s = bc_error("bad token");
4749 static BcStatus bc_parse_parse(BcParse *p)
4753 if (p->l.t.t == BC_LEX_EOF)
4754 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4755 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4756 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
4757 s = bc_parse_func(p);
4760 s = bc_parse_stmt(p);
4762 if (s || G_interrupt) {
4764 s = BC_STATUS_FAILURE;
4770 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4772 BcStatus s = BC_STATUS_SUCCESS;
4773 BcInst prev = BC_INST_PRINT;
4774 BcLexType top, t = p->l.t.t;
4775 size_t nexprs = 0, ops_bgn = p->ops.len;
4776 uint32_t i, nparens, nrelops;
4777 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4779 paren_first = p->l.t.t == BC_LEX_LPAREN;
4780 nparens = nrelops = 0;
4781 paren_expr = rprn = done = get_token = assign = false;
4784 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4790 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4791 rprn = get_token = bin_last = false;
4795 case BC_LEX_OP_MINUS:
4797 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4798 rprn = get_token = false;
4799 bin_last = prev == BC_INST_MINUS;
4803 case BC_LEX_OP_ASSIGN_POWER:
4804 case BC_LEX_OP_ASSIGN_MULTIPLY:
4805 case BC_LEX_OP_ASSIGN_DIVIDE:
4806 case BC_LEX_OP_ASSIGN_MODULUS:
4807 case BC_LEX_OP_ASSIGN_PLUS:
4808 case BC_LEX_OP_ASSIGN_MINUS:
4809 case BC_LEX_OP_ASSIGN:
4811 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4812 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4813 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4815 s = bc_error("bad assignment:"
4816 " left side must be scale,"
4817 " ibase, obase, last, var,"
4824 case BC_LEX_OP_POWER:
4825 case BC_LEX_OP_MULTIPLY:
4826 case BC_LEX_OP_DIVIDE:
4827 case BC_LEX_OP_MODULUS:
4828 case BC_LEX_OP_PLUS:
4829 case BC_LEX_OP_REL_EQ:
4830 case BC_LEX_OP_REL_LE:
4831 case BC_LEX_OP_REL_GE:
4832 case BC_LEX_OP_REL_NE:
4833 case BC_LEX_OP_REL_LT:
4834 case BC_LEX_OP_REL_GT:
4835 case BC_LEX_OP_BOOL_NOT:
4836 case BC_LEX_OP_BOOL_OR:
4837 case BC_LEX_OP_BOOL_AND:
4839 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4840 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4842 return bc_error("bad expression");
4845 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4846 prev = BC_PARSE_TOKEN_INST(t);
4847 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4848 rprn = get_token = false;
4849 bin_last = t != BC_LEX_OP_BOOL_NOT;
4856 if (BC_PARSE_LEAF(prev, rprn))
4857 return bc_error("bad expression");
4859 paren_expr = rprn = bin_last = false;
4861 bc_vec_push(&p->ops, &t);
4868 if (bin_last || prev == BC_INST_BOOL_NOT)
4869 return bc_error("bad expression");
4872 s = BC_STATUS_SUCCESS;
4877 else if (!paren_expr)
4878 return BC_STATUS_PARSE_EMPTY_EXP;
4881 paren_expr = rprn = true;
4882 get_token = bin_last = false;
4884 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4891 if (BC_PARSE_LEAF(prev, rprn))
4892 return bc_error("bad expression");
4894 rprn = get_token = bin_last = false;
4895 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4903 if (BC_PARSE_LEAF(prev, rprn))
4904 return bc_error("bad expression");
4905 bc_parse_number(p, &prev, &nexprs);
4906 paren_expr = get_token = true;
4907 rprn = bin_last = false;
4912 case BC_LEX_KEY_IBASE:
4913 case BC_LEX_KEY_LAST:
4914 case BC_LEX_KEY_OBASE:
4916 if (BC_PARSE_LEAF(prev, rprn))
4917 return bc_error("bad expression");
4918 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4919 bc_parse_push(p, (char) prev);
4921 paren_expr = get_token = true;
4922 rprn = bin_last = false;
4928 case BC_LEX_KEY_LENGTH:
4929 case BC_LEX_KEY_SQRT:
4931 if (BC_PARSE_LEAF(prev, rprn))
4932 return bc_error("bad expression");
4933 s = bc_parse_builtin(p, t, flags, &prev);
4935 rprn = get_token = bin_last = false;
4941 case BC_LEX_KEY_READ:
4943 if (BC_PARSE_LEAF(prev, rprn))
4944 return bc_error("bad expression");
4945 else if (flags & BC_PARSE_NOREAD)
4946 s = bc_error("read() call inside of a read() call");
4948 s = bc_parse_read(p);
4951 rprn = get_token = bin_last = false;
4953 prev = BC_INST_READ;
4958 case BC_LEX_KEY_SCALE:
4960 if (BC_PARSE_LEAF(prev, rprn))
4961 return bc_error("bad expression");
4962 s = bc_parse_scale(p, &prev, flags);
4964 rprn = get_token = bin_last = false;
4966 prev = BC_INST_SCALE;
4973 s = bc_error("bad token");
4978 if (!s && get_token) s = bc_lex_next(&p->l);
4982 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4984 while (p->ops.len > ops_bgn) {
4986 top = BC_PARSE_TOP_OP(p);
4987 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4989 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4990 return bc_error("bad expression");
4992 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4994 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4995 bc_vec_pop(&p->ops);
4998 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4999 return bc_error("bad expression");
5001 for (i = 0; i < next.len; ++i)
5002 if (t == next.tokens[i])
5004 return bc_error("bad expression");
5007 if (!(flags & BC_PARSE_REL) && nrelops) {
5008 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
5011 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5012 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
5016 if (flags & BC_PARSE_PRINT) {
5017 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5018 bc_parse_push(p, BC_INST_POP);
5024 static void bc_parse_init(BcParse *p, size_t func)
5026 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
5029 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5031 return bc_parse_expr(p, flags, bc_parse_next_read);
5036 static BcStatus dc_parse_register(BcParse *p)
5041 s = bc_lex_next(&p->l);
5043 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
5045 name = xstrdup(p->l.t.v.v);
5046 bc_parse_pushName(p, name);
5051 static BcStatus dc_parse_string(BcParse *p)
5053 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5054 size_t idx, len = G.prog.strs.len;
5056 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5059 str = xstrdup(p->l.t.v.v);
5060 bc_parse_push(p, BC_INST_STR);
5061 bc_parse_pushIndex(p, len);
5062 bc_vec_push(&G.prog.strs, &str);
5063 bc_parse_addFunc(p, name, &idx);
5065 return bc_lex_next(&p->l);
5068 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5072 bc_parse_push(p, inst);
5074 s = dc_parse_register(p);
5079 bc_parse_push(p, BC_INST_SWAP);
5080 bc_parse_push(p, BC_INST_ASSIGN);
5081 bc_parse_push(p, BC_INST_POP);
5084 return bc_lex_next(&p->l);
5087 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5091 bc_parse_push(p, inst);
5092 bc_parse_push(p, BC_INST_EXEC_COND);
5094 s = dc_parse_register(p);
5097 s = bc_lex_next(&p->l);
5100 if (p->l.t.t == BC_LEX_ELSE) {
5101 s = dc_parse_register(p);
5103 s = bc_lex_next(&p->l);
5106 bc_parse_push(p, BC_PARSE_STREND);
5111 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5113 BcStatus s = BC_STATUS_SUCCESS;
5116 bool assign, get_token = false;
5120 case BC_LEX_OP_REL_EQ:
5121 case BC_LEX_OP_REL_LE:
5122 case BC_LEX_OP_REL_GE:
5123 case BC_LEX_OP_REL_NE:
5124 case BC_LEX_OP_REL_LT:
5125 case BC_LEX_OP_REL_GT:
5127 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5134 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5140 s = dc_parse_string(p);
5147 if (t == BC_LEX_NEG) {
5148 s = bc_lex_next(&p->l);
5150 if (p->l.t.t != BC_LEX_NUMBER)
5151 return bc_error("bad token");
5154 bc_parse_number(p, &prev, &p->nbraces);
5156 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5162 case BC_LEX_KEY_READ:
5164 if (flags & BC_PARSE_NOREAD)
5165 s = bc_error("read() call inside of a read() call");
5167 bc_parse_push(p, BC_INST_READ);
5172 case BC_LEX_OP_ASSIGN:
5173 case BC_LEX_STORE_PUSH:
5175 assign = t == BC_LEX_OP_ASSIGN;
5176 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5177 s = dc_parse_mem(p, inst, true, assign);
5182 case BC_LEX_LOAD_POP:
5184 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5185 s = dc_parse_mem(p, inst, true, false);
5189 case BC_LEX_STORE_IBASE:
5190 case BC_LEX_STORE_SCALE:
5191 case BC_LEX_STORE_OBASE:
5193 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5194 s = dc_parse_mem(p, inst, false, true);
5200 s = bc_error("bad token");
5206 if (!s && get_token) s = bc_lex_next(&p->l);
5211 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5213 BcStatus s = BC_STATUS_SUCCESS;
5217 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5219 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5221 inst = dc_parse_insts[t];
5223 if (inst != BC_INST_INVALID) {
5224 bc_parse_push(p, inst);
5225 s = bc_lex_next(&p->l);
5228 s = dc_parse_token(p, t, flags);
5231 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5232 bc_parse_push(p, BC_INST_POP_EXEC);
5237 static BcStatus dc_parse_parse(BcParse *p)
5241 if (p->l.t.t == BC_LEX_EOF)
5242 s = bc_error("end of file");
5244 s = dc_parse_expr(p, 0);
5246 if (s || G_interrupt) {
5248 s = BC_STATUS_FAILURE;
5254 static void dc_parse_init(BcParse *p, size_t func)
5256 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5260 static void common_parse_init(BcParse *p, size_t func)
5263 bc_parse_init(p, func);
5265 dc_parse_init(p, func);
5269 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5272 return bc_parse_expression(p, flags);
5274 return dc_parse_expr(p, flags);
5278 static BcVec* bc_program_search(char *id, bool var)
5286 v = var ? &G.prog.vars : &G.prog.arrs;
5287 map = var ? &G.prog.var_map : &G.prog.arr_map;
5291 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5294 bc_array_init(&data.v, var);
5295 bc_vec_push(v, &data.v);
5298 ptr = bc_vec_item(map, i);
5299 if (new) ptr->name = xstrdup(e.name);
5300 return bc_vec_item(v, ptr->idx);
5303 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5305 BcStatus s = BC_STATUS_SUCCESS;
5310 case BC_RESULT_TEMP:
5311 case BC_RESULT_IBASE:
5312 case BC_RESULT_SCALE:
5313 case BC_RESULT_OBASE:
5319 case BC_RESULT_CONSTANT:
5321 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5322 size_t base_t, len = strlen(*str);
5325 bc_num_init(&r->d.n, len);
5327 hex = hex && len == 1;
5328 base = hex ? &G.prog.hexb : &G.prog.ib;
5329 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5330 s = bc_num_parse(&r->d.n, *str, base, base_t);
5333 bc_num_free(&r->d.n);
5338 r->t = BC_RESULT_TEMP;
5344 case BC_RESULT_ARRAY:
5345 case BC_RESULT_ARRAY_ELEM:
5349 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5351 if (r->t == BC_RESULT_ARRAY_ELEM) {
5353 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5354 *num = bc_vec_item(v, r->d.id.idx);
5357 *num = bc_vec_top(v);
5362 case BC_RESULT_LAST:
5364 *num = &G.prog.last;
5378 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5379 BcResult **r, BcNum **rn, bool assign)
5383 BcResultType lt, rt;
5385 if (!BC_PROG_STACK(&G.prog.results, 2))
5386 return bc_error("stack has too few elements");
5388 *r = bc_vec_item_rev(&G.prog.results, 0);
5389 *l = bc_vec_item_rev(&G.prog.results, 1);
5393 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5395 s = bc_program_num(*l, ln, false);
5397 s = bc_program_num(*r, rn, hex);
5400 // We run this again under these conditions in case any vector has been
5401 // reallocated out from under the BcNums or arrays we had.
5402 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5403 s = bc_program_num(*l, ln, false);
5407 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5408 return bc_error("variable is wrong type");
5409 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5410 return bc_error("variable is wrong type");
5415 static void bc_program_binOpRetire(BcResult *r)
5417 r->t = BC_RESULT_TEMP;
5418 bc_vec_pop(&G.prog.results);
5419 bc_vec_pop(&G.prog.results);
5420 bc_vec_push(&G.prog.results, r);
5423 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5427 if (!BC_PROG_STACK(&G.prog.results, 1))
5428 return bc_error("stack has too few elements");
5429 *r = bc_vec_top(&G.prog.results);
5431 s = bc_program_num(*r, n, false);
5434 if (!BC_PROG_NUM((*r), (*n)))
5435 return bc_error("variable is wrong type");
5440 static void bc_program_retire(BcResult *r, BcResultType t)
5443 bc_vec_pop(&G.prog.results);
5444 bc_vec_push(&G.prog.results, r);
5447 static BcStatus bc_program_op(char inst)
5450 BcResult *opd1, *opd2, res;
5451 BcNum *n1, *n2 = NULL;
5453 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5455 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5457 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5459 bc_program_binOpRetire(&res);
5464 bc_num_free(&res.d.n);
5468 static BcStatus bc_program_read(void)
5475 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5477 for (i = 0; i < G.prog.stack.len; ++i) {
5478 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5479 if (ip_ptr->func == BC_PROG_READ)
5480 return bc_error("read() call inside of a read() call");
5483 bc_vec_pop_all(&f->code);
5484 bc_char_vec_init(&buf);
5486 s = bc_read_line(&buf, "read> ");
5489 common_parse_init(&parse, BC_PROG_READ);
5490 bc_lex_file(&parse.l, bc_program_stdin_name);
5492 s = bc_parse_text(&parse, buf.v);
5493 if (s) goto exec_err;
5494 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5495 if (s) goto exec_err;
5497 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5498 s = bc_error("bad read() expression");
5502 ip.func = BC_PROG_READ;
5504 ip.len = G.prog.results.len;
5506 // Update this pointer, just in case.
5507 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5509 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5510 bc_vec_push(&G.prog.stack, &ip);
5513 bc_parse_free(&parse);
5519 static size_t bc_program_index(char *code, size_t *bgn)
5521 char amt = code[(*bgn)++], i = 0;
5524 for (; i < amt; ++i, ++(*bgn))
5525 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5530 static char *bc_program_name(char *code, size_t *bgn)
5533 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5535 s = xmalloc(ptr - str + 1);
5538 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5546 static void bc_program_printString(const char *str, size_t *nchars)
5548 size_t i, len = strlen(str);
5557 for (i = 0; i < len; ++i, ++(*nchars)) {
5561 if (c != '\\' || i == len - 1)
5621 // Just print the backslash and following character.
5632 static BcStatus bc_program_print(char inst, size_t idx)
5634 BcStatus s = BC_STATUS_SUCCESS;
5639 bool pop = inst != BC_INST_PRINT;
5641 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5642 return bc_error("stack has too few elements");
5644 r = bc_vec_item_rev(&G.prog.results, idx);
5645 s = bc_program_num(r, &num, false);
5648 if (BC_PROG_NUM(r, num)) {
5649 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5650 if (!s) bc_num_copy(&G.prog.last, num);
5654 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5655 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5657 if (inst == BC_INST_PRINT_STR) {
5658 for (i = 0, len = strlen(str); i < len; ++i) {
5661 if (c == '\n') G.prog.nchars = SIZE_MAX;
5666 bc_program_printString(str, &G.prog.nchars);
5667 if (inst == BC_INST_PRINT) bb_putchar('\n');
5671 if (!s && pop) bc_vec_pop(&G.prog.results);
5676 static BcStatus bc_program_negate(void)
5682 s = bc_program_prep(&ptr, &num);
5685 bc_num_init(&res.d.n, num->len);
5686 bc_num_copy(&res.d.n, num);
5687 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5689 bc_program_retire(&res, BC_RESULT_TEMP);
5694 static BcStatus bc_program_logical(char inst)
5697 BcResult *opd1, *opd2, res;
5702 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5704 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5706 if (inst == BC_INST_BOOL_AND)
5707 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5708 else if (inst == BC_INST_BOOL_OR)
5709 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5712 cmp = bc_num_cmp(n1, n2);
5716 case BC_INST_REL_EQ:
5722 case BC_INST_REL_LE:
5728 case BC_INST_REL_GE:
5734 case BC_INST_REL_NE:
5740 case BC_INST_REL_LT:
5746 case BC_INST_REL_GT:
5754 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5756 bc_program_binOpRetire(&res);
5762 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5768 memset(&n2, 0, sizeof(BcNum));
5769 n2.rdx = res.d.id.idx = r->d.id.idx;
5770 res.t = BC_RESULT_STR;
5773 if (!BC_PROG_STACK(&G.prog.results, 2))
5774 return bc_error("stack has too few elements");
5776 bc_vec_pop(&G.prog.results);
5779 bc_vec_pop(&G.prog.results);
5781 bc_vec_push(&G.prog.results, &res);
5782 bc_vec_push(v, &n2);
5784 return BC_STATUS_SUCCESS;
5788 static BcStatus bc_program_copyToVar(char *name, bool var)
5795 if (!BC_PROG_STACK(&G.prog.results, 1))
5796 return bc_error("stack has too few elements");
5798 ptr = bc_vec_top(&G.prog.results);
5799 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5800 return bc_error("variable is wrong type");
5801 v = bc_program_search(name, var);
5804 if (ptr->t == BC_RESULT_STR && !var)
5805 return bc_error("variable is wrong type");
5806 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5809 s = bc_program_num(ptr, &n, false);
5812 // Do this once more to make sure that pointers were not invalidated.
5813 v = bc_program_search(name, var);
5816 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5817 bc_num_copy(&r.d.n, n);
5820 bc_array_init(&r.d.v, true);
5821 bc_array_copy(&r.d.v, (BcVec *) n);
5824 bc_vec_push(v, &r.d);
5825 bc_vec_pop(&G.prog.results);
5830 static BcStatus bc_program_assign(char inst)
5833 BcResult *left, *right, res;
5834 BcNum *l = NULL, *r = NULL;
5835 unsigned long val, max;
5836 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5838 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5841 ib = left->t == BC_RESULT_IBASE;
5842 sc = left->t == BC_RESULT_SCALE;
5846 if (right->t == BC_RESULT_STR) {
5850 if (left->t != BC_RESULT_VAR)
5851 return bc_error("variable is wrong type");
5852 v = bc_program_search(left->d.id.name, true);
5854 return bc_program_assignStr(right, v, false);
5858 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5859 return bc_error("bad assignment:"
5860 " left side must be scale,"
5861 " ibase, obase, last, var,"
5866 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5867 return bc_error("divide by zero");
5872 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5879 if (ib || sc || left->t == BC_RESULT_OBASE) {
5880 static const char *const msg[] = {
5881 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5882 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5883 "?1", //BC_RESULT_LAST
5884 "?2", //BC_RESULT_CONSTANT
5885 "?3", //BC_RESULT_ONE
5886 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5890 s = bc_num_ulong(l, &val);
5893 s = left->t - BC_RESULT_IBASE;
5896 ptr = &G.prog.scale;
5899 if (val < BC_NUM_MIN_BASE)
5900 return bc_error(msg[s]);
5901 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5902 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5906 return bc_error(msg[s]);
5908 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5910 *ptr = (size_t) val;
5911 s = BC_STATUS_SUCCESS;
5914 bc_num_init(&res.d.n, l->len);
5915 bc_num_copy(&res.d.n, l);
5916 bc_program_binOpRetire(&res);
5922 #define bc_program_pushVar(code, bgn, pop, copy) \
5923 bc_program_pushVar(code, bgn)
5924 // for bc, 'pop' and 'copy' are always false
5926 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5927 bool pop, bool copy)
5929 BcStatus s = BC_STATUS_SUCCESS;
5931 char *name = bc_program_name(code, bgn);
5933 r.t = BC_RESULT_VAR;
5938 BcVec *v = bc_program_search(name, true);
5939 BcNum *num = bc_vec_top(v);
5943 if (!BC_PROG_STACK(v, 2 - copy)) {
5945 return bc_error("stack has too few elements");
5951 if (!BC_PROG_STR(num)) {
5953 r.t = BC_RESULT_TEMP;
5955 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5956 bc_num_copy(&r.d.n, num);
5959 r.t = BC_RESULT_STR;
5960 r.d.id.idx = num->rdx;
5963 if (!copy) bc_vec_pop(v);
5968 bc_vec_push(&G.prog.results, &r);
5973 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5976 BcStatus s = BC_STATUS_SUCCESS;
5980 r.d.id.name = bc_program_name(code, bgn);
5982 if (inst == BC_INST_ARRAY) {
5983 r.t = BC_RESULT_ARRAY;
5984 bc_vec_push(&G.prog.results, &r);
5991 s = bc_program_prep(&operand, &num);
5993 s = bc_num_ulong(num, &temp);
5996 if (temp > BC_MAX_DIM) {
5997 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
6001 r.d.id.idx = (size_t) temp;
6002 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
6006 if (s) free(r.d.id.name);
6011 static BcStatus bc_program_incdec(char inst)
6014 BcResult *ptr, res, copy;
6018 s = bc_program_prep(&ptr, &num);
6021 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6022 copy.t = BC_RESULT_TEMP;
6023 bc_num_init(©.d.n, num->len);
6024 bc_num_copy(©.d.n, num);
6027 res.t = BC_RESULT_ONE;
6028 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6029 BC_INST_ASSIGN_PLUS :
6030 BC_INST_ASSIGN_MINUS;
6032 bc_vec_push(&G.prog.results, &res);
6033 bc_program_assign(inst);
6035 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
6036 bc_vec_pop(&G.prog.results);
6037 bc_vec_push(&G.prog.results, ©);
6043 static BcStatus bc_program_call(char *code, size_t *idx)
6045 BcStatus s = BC_STATUS_SUCCESS;
6047 size_t i, nparams = bc_program_index(code, idx);
6054 ip.func = bc_program_index(code, idx);
6055 func = bc_vec_item(&G.prog.fns, ip.func);
6057 if (func->code.len == 0) {
6058 return bc_error("undefined function");
6060 if (nparams != func->nparams) {
6061 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
6063 ip.len = G.prog.results.len - nparams;
6065 for (i = 0; i < nparams; ++i) {
6067 a = bc_vec_item(&func->autos, nparams - 1 - i);
6068 arg = bc_vec_top(&G.prog.results);
6070 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6071 return bc_error("variable is wrong type");
6073 s = bc_program_copyToVar(a->name, a->idx);
6077 for (; i < func->autos.len; ++i) {
6080 a = bc_vec_item(&func->autos, i);
6081 v = bc_program_search(a->name, a->idx);
6084 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6085 bc_vec_push(v, ¶m.n);
6088 bc_array_init(¶m.v, true);
6089 bc_vec_push(v, ¶m.v);
6093 bc_vec_push(&G.prog.stack, &ip);
6095 return BC_STATUS_SUCCESS;
6098 static BcStatus bc_program_return(char inst)
6104 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6106 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6107 return bc_error("stack has too few elements");
6109 f = bc_vec_item(&G.prog.fns, ip->func);
6110 res.t = BC_RESULT_TEMP;
6112 if (inst == BC_INST_RET) {
6115 BcResult *operand = bc_vec_top(&G.prog.results);
6117 s = bc_program_num(operand, &num, false);
6119 bc_num_init(&res.d.n, num->len);
6120 bc_num_copy(&res.d.n, num);
6123 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6124 bc_num_zero(&res.d.n);
6127 // We need to pop arguments as well, so this takes that into account.
6128 for (i = 0; i < f->autos.len; ++i) {
6131 BcId *a = bc_vec_item(&f->autos, i);
6133 v = bc_program_search(a->name, a->idx);
6137 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6138 bc_vec_push(&G.prog.results, &res);
6139 bc_vec_pop(&G.prog.stack);
6141 return BC_STATUS_SUCCESS;
6145 static unsigned long bc_program_scale(BcNum *n)
6147 return (unsigned long) n->rdx;
6150 static unsigned long bc_program_len(BcNum *n)
6152 unsigned long len = n->len;
6155 if (n->rdx != n->len) return len;
6156 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6161 static BcStatus bc_program_builtin(char inst)
6167 bool len = inst == BC_INST_LENGTH;
6169 if (!BC_PROG_STACK(&G.prog.results, 1))
6170 return bc_error("stack has too few elements");
6171 opnd = bc_vec_top(&G.prog.results);
6173 s = bc_program_num(opnd, &num, false);
6177 if (!BC_PROG_NUM(opnd, num) && !len)
6178 return bc_error("variable is wrong type");
6181 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6183 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6185 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6186 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6190 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6193 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6195 str = bc_vec_item(&G.prog.strs, idx);
6196 bc_num_ulong2num(&res.d.n, strlen(*str));
6200 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6201 bc_num_ulong2num(&res.d.n, f(num));
6204 bc_program_retire(&res, BC_RESULT_TEMP);
6210 static BcStatus bc_program_divmod(void)
6213 BcResult *opd1, *opd2, res, res2;
6214 BcNum *n1, *n2 = NULL;
6216 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6219 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6220 bc_num_init(&res2.d.n, n2->len);
6222 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6225 bc_program_binOpRetire(&res2);
6226 res.t = BC_RESULT_TEMP;
6227 bc_vec_push(&G.prog.results, &res);
6232 bc_num_free(&res2.d.n);
6233 bc_num_free(&res.d.n);
6237 static BcStatus bc_program_modexp(void)
6240 BcResult *r1, *r2, *r3, res;
6241 BcNum *n1, *n2, *n3;
6243 if (!BC_PROG_STACK(&G.prog.results, 3))
6244 return bc_error("stack has too few elements");
6245 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6248 r1 = bc_vec_item_rev(&G.prog.results, 2);
6249 s = bc_program_num(r1, &n1, false);
6251 if (!BC_PROG_NUM(r1, n1))
6252 return bc_error("variable is wrong type");
6254 // Make sure that the values have their pointers updated, if necessary.
6255 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6257 if (r1->t == r2->t) {
6258 s = bc_program_num(r2, &n2, false);
6262 if (r1->t == r3->t) {
6263 s = bc_program_num(r3, &n3, false);
6268 bc_num_init(&res.d.n, n3->len);
6269 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6272 bc_vec_pop(&G.prog.results);
6273 bc_program_binOpRetire(&res);
6278 bc_num_free(&res.d.n);
6282 static void bc_program_stackLen(void)
6285 size_t len = G.prog.results.len;
6287 res.t = BC_RESULT_TEMP;
6289 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6290 bc_num_ulong2num(&res.d.n, len);
6291 bc_vec_push(&G.prog.results, &res);
6294 static BcStatus bc_program_asciify(void)
6298 BcNum *num = NULL, n;
6299 char *str, *str2, c;
6300 size_t len = G.prog.strs.len, idx;
6303 if (!BC_PROG_STACK(&G.prog.results, 1))
6304 return bc_error("stack has too few elements");
6305 r = bc_vec_top(&G.prog.results);
6307 s = bc_program_num(r, &num, false);
6310 if (BC_PROG_NUM(r, num)) {
6312 bc_num_init(&n, BC_NUM_DEF_SIZE);
6313 bc_num_copy(&n, num);
6314 bc_num_truncate(&n, n.rdx);
6316 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6317 if (s) goto num_err;
6318 s = bc_num_ulong(&n, &val);
6319 if (s) goto num_err;
6326 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6327 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6335 str2 = xstrdup(str);
6336 bc_program_addFunc(str2, &idx);
6338 if (idx != len + BC_PROG_REQ_FUNCS) {
6340 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6341 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6350 bc_vec_push(&G.prog.strs, &str);
6352 res.t = BC_RESULT_STR;
6354 bc_vec_pop(&G.prog.results);
6355 bc_vec_push(&G.prog.results, &res);
6357 return BC_STATUS_SUCCESS;
6364 static BcStatus bc_program_printStream(void)
6372 if (!BC_PROG_STACK(&G.prog.results, 1))
6373 return bc_error("stack has too few elements");
6374 r = bc_vec_top(&G.prog.results);
6376 s = bc_program_num(r, &n, false);
6379 if (BC_PROG_NUM(r, n))
6380 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6382 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6383 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6390 static BcStatus bc_program_nquit(void)
6397 s = bc_program_prep(&opnd, &num);
6399 s = bc_num_ulong(num, &val);
6402 bc_vec_pop(&G.prog.results);
6404 if (G.prog.stack.len < val)
6405 return bc_error("stack has too few elements");
6406 if (G.prog.stack.len == val)
6409 bc_vec_npop(&G.prog.stack, val);
6414 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6417 BcStatus s = BC_STATUS_SUCCESS;
6427 if (!BC_PROG_STACK(&G.prog.results, 1))
6428 return bc_error("stack has too few elements");
6430 r = bc_vec_top(&G.prog.results);
6434 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6436 if (code[*bgn] == BC_PARSE_STREND)
6439 else_name = bc_program_name(code, bgn);
6441 exec = r->d.n.len != 0;
6445 else if (else_name != NULL) {
6452 v = bc_program_search(name, true);
6459 if (!exec) goto exit;
6460 if (!BC_PROG_STR(n)) {
6461 s = bc_error("variable is wrong type");
6469 if (r->t == BC_RESULT_STR)
6471 else if (r->t == BC_RESULT_VAR) {
6472 s = bc_program_num(r, &n, false);
6473 if (s || !BC_PROG_STR(n)) goto exit;
6480 fidx = sidx + BC_PROG_REQ_FUNCS;
6482 str = bc_vec_item(&G.prog.strs, sidx);
6483 f = bc_vec_item(&G.prog.fns, fidx);
6485 if (f->code.len == 0) {
6486 common_parse_init(&prs, fidx);
6487 s = bc_parse_text(&prs, *str);
6489 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6492 if (prs.l.t.t != BC_LEX_EOF) {
6493 s = bc_error("bad expression");
6497 bc_parse_free(&prs);
6501 ip.len = G.prog.results.len;
6504 bc_vec_pop(&G.prog.results);
6505 bc_vec_push(&G.prog.stack, &ip);
6507 return BC_STATUS_SUCCESS;
6510 bc_parse_free(&prs);
6511 f = bc_vec_item(&G.prog.fns, fidx);
6512 bc_vec_pop_all(&f->code);
6514 bc_vec_pop(&G.prog.results);
6519 static void bc_program_pushGlobal(char inst)
6524 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6525 if (inst == BC_INST_IBASE)
6526 val = (unsigned long) G.prog.ib_t;
6527 else if (inst == BC_INST_SCALE)
6528 val = (unsigned long) G.prog.scale;
6530 val = (unsigned long) G.prog.ob_t;
6532 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6533 bc_num_ulong2num(&res.d.n, val);
6534 bc_vec_push(&G.prog.results, &res);
6537 static void bc_program_addFunc(char *name, size_t *idx)
6539 BcId entry, *entry_ptr;
6544 entry.idx = G.prog.fns.len;
6546 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6547 if (!inserted) free(name);
6549 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6550 *idx = entry_ptr->idx;
6554 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6556 // We need to reset these, so the function can be repopulated.
6558 bc_vec_pop_all(&func->autos);
6559 bc_vec_pop_all(&func->code);
6560 bc_vec_pop_all(&func->labels);
6564 bc_vec_push(&G.prog.fns, &f);
6568 // Called when parsing or execution detects a failure,
6569 // resets execution structures.
6570 static void bc_program_reset(void)
6575 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6576 bc_vec_pop_all(&G.prog.results);
6578 f = bc_vec_item(&G.prog.fns, 0);
6579 ip = bc_vec_top(&G.prog.stack);
6580 ip->idx = f->code.len;
6582 // If !tty, no need to check for ^C: we don't have ^C handler,
6583 // we would be killed by a signal and won't reach this place
6586 static BcStatus bc_program_exec(void)
6588 BcStatus s = BC_STATUS_SUCCESS;
6592 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6593 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6594 char *code = func->code.v;
6597 while (!s && ip->idx < func->code.len) {
6599 char inst = code[(ip->idx)++];
6604 case BC_INST_JUMP_ZERO:
6606 s = bc_program_prep(&ptr, &num);
6608 cond = !bc_num_cmp(num, &G.prog.zero);
6609 bc_vec_pop(&G.prog.results);
6615 idx = bc_program_index(code, &ip->idx);
6616 addr = bc_vec_item(&func->labels, idx);
6617 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6623 s = bc_program_call(code, &ip->idx);
6627 case BC_INST_INC_PRE:
6628 case BC_INST_DEC_PRE:
6629 case BC_INST_INC_POST:
6630 case BC_INST_DEC_POST:
6632 s = bc_program_incdec(inst);
6645 s = bc_program_return(inst);
6649 case BC_INST_BOOL_OR:
6650 case BC_INST_BOOL_AND:
6652 case BC_INST_REL_EQ:
6653 case BC_INST_REL_LE:
6654 case BC_INST_REL_GE:
6655 case BC_INST_REL_NE:
6656 case BC_INST_REL_LT:
6657 case BC_INST_REL_GT:
6659 s = bc_program_logical(inst);
6665 s = bc_program_read();
6671 s = bc_program_pushVar(code, &ip->idx, false, false);
6675 case BC_INST_ARRAY_ELEM:
6678 s = bc_program_pushArray(code, &ip->idx, inst);
6684 r.t = BC_RESULT_LAST;
6685 bc_vec_push(&G.prog.results, &r);
6693 bc_program_pushGlobal(inst);
6697 case BC_INST_SCALE_FUNC:
6698 case BC_INST_LENGTH:
6701 s = bc_program_builtin(inst);
6707 r.t = BC_RESULT_CONSTANT;
6708 r.d.id.idx = bc_program_index(code, &ip->idx);
6709 bc_vec_push(&G.prog.results, &r);
6715 if (!BC_PROG_STACK(&G.prog.results, 1))
6716 s = bc_error("stack has too few elements");
6718 bc_vec_pop(&G.prog.results);
6722 case BC_INST_POP_EXEC:
6724 bc_vec_pop(&G.prog.stack);
6729 case BC_INST_PRINT_POP:
6730 case BC_INST_PRINT_STR:
6732 s = bc_program_print(inst, 0);
6738 r.t = BC_RESULT_STR;
6739 r.d.id.idx = bc_program_index(code, &ip->idx);
6740 bc_vec_push(&G.prog.results, &r);
6745 case BC_INST_MULTIPLY:
6746 case BC_INST_DIVIDE:
6747 case BC_INST_MODULUS:
6751 s = bc_program_op(inst);
6755 case BC_INST_BOOL_NOT:
6757 s = bc_program_prep(&ptr, &num);
6760 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6761 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6762 bc_program_retire(&r, BC_RESULT_TEMP);
6769 s = bc_program_negate();
6774 case BC_INST_ASSIGN_POWER:
6775 case BC_INST_ASSIGN_MULTIPLY:
6776 case BC_INST_ASSIGN_DIVIDE:
6777 case BC_INST_ASSIGN_MODULUS:
6778 case BC_INST_ASSIGN_PLUS:
6779 case BC_INST_ASSIGN_MINUS:
6781 case BC_INST_ASSIGN:
6783 s = bc_program_assign(inst);
6787 case BC_INST_MODEXP:
6789 s = bc_program_modexp();
6793 case BC_INST_DIVMOD:
6795 s = bc_program_divmod();
6799 case BC_INST_EXECUTE:
6800 case BC_INST_EXEC_COND:
6802 cond = inst == BC_INST_EXEC_COND;
6803 s = bc_program_execStr(code, &ip->idx, cond);
6807 case BC_INST_PRINT_STACK:
6809 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6810 s = bc_program_print(BC_INST_PRINT, idx);
6814 case BC_INST_CLEAR_STACK:
6816 bc_vec_pop_all(&G.prog.results);
6820 case BC_INST_STACK_LEN:
6822 bc_program_stackLen();
6826 case BC_INST_DUPLICATE:
6828 if (!BC_PROG_STACK(&G.prog.results, 1))
6829 return bc_error("stack has too few elements");
6830 ptr = bc_vec_top(&G.prog.results);
6831 bc_result_copy(&r, ptr);
6832 bc_vec_push(&G.prog.results, &r);
6840 if (!BC_PROG_STACK(&G.prog.results, 2))
6841 return bc_error("stack has too few elements");
6843 ptr = bc_vec_item_rev(&G.prog.results, 0);
6844 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6845 memcpy(&r, ptr, sizeof(BcResult));
6846 memcpy(ptr, ptr2, sizeof(BcResult));
6847 memcpy(ptr2, &r, sizeof(BcResult));
6852 case BC_INST_ASCIIFY:
6854 s = bc_program_asciify();
6858 case BC_INST_PRINT_STREAM:
6860 s = bc_program_printStream();
6865 case BC_INST_PUSH_VAR:
6867 bool copy = inst == BC_INST_LOAD;
6868 s = bc_program_pushVar(code, &ip->idx, true, copy);
6872 case BC_INST_PUSH_TO_VAR:
6874 char *name = bc_program_name(code, &ip->idx);
6875 s = bc_program_copyToVar(name, true);
6882 if (G.prog.stack.len <= 2)
6884 bc_vec_npop(&G.prog.stack, 2);
6890 s = bc_program_nquit();
6896 if (s || G_interrupt) {
6901 // If the stack has changed, pointers may be invalid.
6902 ip = bc_vec_top(&G.prog.stack);
6903 func = bc_vec_item(&G.prog.fns, ip->func);
6904 code = func->code.v;
6910 static void bc_vm_info(void)
6912 printf("%s "BB_VER"\n"
6913 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6914 "Report bugs at: https://github.com/gavinhoward/bc\n"
6915 "This is free software with ABSOLUTELY NO WARRANTY\n"
6920 static void bc_vm_envArgs(void)
6922 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6925 char *env_args = getenv(bc_args_env_name), *buf;
6927 if (!env_args) return;
6929 G.env_args = xstrdup(env_args);
6932 bc_vec_init(&v, sizeof(char *), NULL);
6933 bc_vec_push(&v, &bc_args_env_name);
6936 if (!isspace(*buf)) {
6937 bc_vec_push(&v, &buf);
6938 while (*buf != 0 && !isspace(*buf)) ++buf;
6939 if (*buf != 0) (*(buf++)) = '\0';
6945 bc_args((int) v.len, (char **) v.v);
6951 static size_t bc_vm_envLen(const char *var)
6953 char *lenv = getenv(var);
6954 size_t i, len = BC_NUM_PRINT_WIDTH;
6957 if (!lenv) return len;
6961 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6963 len = (size_t) atoi(lenv) - 1;
6964 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6967 len = BC_NUM_PRINT_WIDTH;
6972 static BcStatus bc_vm_process(const char *text)
6974 BcStatus s = bc_parse_text(&G.prs, text);
6978 while (G.prs.l.t.t != BC_LEX_EOF) {
6979 s = G.prs.parse(&G.prs);
6983 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6984 s = bc_program_exec();
6993 static BcStatus bc_vm_file(const char *file)
7001 data = bc_read_file(file);
7002 if (!data) return bc_error("file '%s' is not text", file);
7004 bc_lex_file(&G.prs.l, file);
7005 s = bc_vm_process(data);
7008 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7009 ip = bc_vec_item(&G.prog.stack, 0);
7011 if (main_func->code.len < ip->idx)
7012 s = bc_error("file '%s' is not executable", file);
7019 static BcStatus bc_vm_stdin(void)
7023 size_t len, i, str = 0;
7024 bool comment = false;
7026 G.prog.file = bc_program_stdin_name;
7027 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7029 bc_char_vec_init(&buffer);
7030 bc_char_vec_init(&buf);
7031 bc_vec_pushByte(&buffer, '\0');
7033 // This loop is complex because the vm tries not to send any lines that end
7034 // with a backslash to the parser. The reason for that is because the parser
7035 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7036 // case, and for strings and comments, the parser will expect more stuff.
7037 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7039 char *string = buf.v;
7044 if (str && buf.v[0] == G.send)
7046 else if (buf.v[0] == G.sbgn)
7049 else if (len > 1 || comment) {
7051 for (i = 0; i < len; ++i) {
7053 bool notend = len > i + 1;
7056 if (i - 1 > len || string[i - 1] != '\\') {
7057 if (G.sbgn == G.send)
7059 else if (c == G.send)
7061 else if (c == G.sbgn)
7065 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7069 else if (c == '*' && notend && comment && string[i + 1] == '/')
7073 if (str || comment || string[len - 2] == '\\') {
7074 bc_vec_concat(&buffer, buf.v);
7079 bc_vec_concat(&buffer, buf.v);
7080 s = bc_vm_process(buffer.v);
7083 fputs("ready for more input\n", stderr);
7086 bc_vec_pop_all(&buffer);
7090 s = bc_error("string end could not be found");
7093 s = bc_error("comment end could not be found");
7097 bc_vec_free(&buffer);
7101 static BcStatus bc_vm_exec(void)
7103 BcStatus s = BC_STATUS_SUCCESS;
7107 if (option_mask32 & BC_FLAG_L) {
7109 bc_lex_file(&G.prs.l, bc_lib_name);
7110 s = bc_parse_text(&G.prs, bc_lib);
7112 while (!s && G.prs.l.t.t != BC_LEX_EOF)
7113 s = G.prs.parse(&G.prs);
7116 s = bc_program_exec();
7121 for (i = 0; !s && i < G.files.len; ++i)
7122 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7125 fputs("ready for more input\n", stderr);
7128 if (IS_BC || !G.files.len)
7130 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7131 s = bc_vm_process("");
7136 #if ENABLE_FEATURE_CLEAN_UP
7137 static void bc_program_free()
7139 bc_num_free(&G.prog.ib);
7140 bc_num_free(&G.prog.ob);
7141 bc_num_free(&G.prog.hexb);
7143 bc_num_free(&G.prog.strmb);
7145 bc_vec_free(&G.prog.fns);
7146 bc_vec_free(&G.prog.fn_map);
7147 bc_vec_free(&G.prog.vars);
7148 bc_vec_free(&G.prog.var_map);
7149 bc_vec_free(&G.prog.arrs);
7150 bc_vec_free(&G.prog.arr_map);
7151 bc_vec_free(&G.prog.strs);
7152 bc_vec_free(&G.prog.consts);
7153 bc_vec_free(&G.prog.results);
7154 bc_vec_free(&G.prog.stack);
7155 bc_num_free(&G.prog.last);
7156 bc_num_free(&G.prog.zero);
7157 bc_num_free(&G.prog.one);
7160 static void bc_vm_free(void)
7162 bc_vec_free(&G.files);
7164 bc_parse_free(&G.prs);
7169 static void bc_program_init(size_t line_len)
7174 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7175 memset(&ip, 0, sizeof(BcInstPtr));
7177 /* G.prog.nchars = G.prog.scale = 0; - already is */
7178 G.prog.len = line_len;
7180 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7181 bc_num_ten(&G.prog.ib);
7184 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7185 bc_num_ten(&G.prog.ob);
7188 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7189 bc_num_ten(&G.prog.hexb);
7190 G.prog.hexb.num[0] = 6;
7193 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7194 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7197 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7198 bc_num_zero(&G.prog.last);
7200 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7201 bc_num_zero(&G.prog.zero);
7203 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7204 bc_num_one(&G.prog.one);
7206 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7207 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
7209 bc_program_addFunc(xstrdup("(main)"), &idx);
7210 bc_program_addFunc(xstrdup("(read)"), &idx);
7212 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7213 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
7215 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7216 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7218 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7219 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7220 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7221 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7222 bc_vec_push(&G.prog.stack, &ip);
7225 static void bc_vm_init(const char *env_len)
7227 size_t len = bc_vm_envLen(env_len);
7229 bc_vec_init(&G.files, sizeof(char *), NULL);
7235 bc_program_init(len);
7237 bc_parse_init(&G.prs, BC_PROG_MAIN);
7239 dc_parse_init(&G.prs, BC_PROG_MAIN);
7243 static BcStatus bc_vm_run(int argc, char *argv[],
7244 const char *env_len)
7248 bc_vm_init(env_len);
7249 bc_args(argc, argv);
7251 G.ttyin = isatty(0);
7254 #if ENABLE_FEATURE_BC_SIGNALS
7255 // With SA_RESTART, most system calls will restart
7256 // (IOW: they won't fail with EINTR).
7257 // In particular, this means ^C won't cause
7258 // stdout to get into "error state" if SIGINT hits
7259 // within write() syscall.
7260 // The downside is that ^C while line input is taken
7261 // will only be handled after [Enter] since read()
7262 // from stdin is not interrupted by ^C either,
7263 // it restarts, thus fgetc() does not return on ^C.
7264 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7266 // Without SA_RESTART, this exhibits a bug:
7267 // "while (1) print 1" and try ^C-ing it.
7268 // Intermittently, instead of returning to input line,
7269 // you'll get "output error: Interrupted system call"
7271 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7273 if (!(option_mask32 & BC_FLAG_Q))
7278 #if ENABLE_FEATURE_CLEAN_UP
7285 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7286 int bc_main(int argc, char **argv)
7289 G.sbgn = G.send = '"';
7291 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7296 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7297 int dc_main(int argc, char **argv)
7303 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");