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
175 // BC_STATUS_ALLOC_ERR,
176 // BC_STATUS_INPUT_EOF,
177 // BC_STATUS_BIN_FILE,
178 // BC_STATUS_PATH_IS_DIR,
180 // BC_STATUS_LEX_BAD_CHAR,
181 // BC_STATUS_LEX_NO_STRING_END,
182 // BC_STATUS_LEX_NO_COMMENT_END,
183 // BC_STATUS_LEX_EOF,
185 // BC_STATUS_LEX_EXTENDED_REG,
187 // BC_STATUS_PARSE_BAD_TOKEN,
188 // BC_STATUS_PARSE_BAD_EXP,
189 // BC_STATUS_PARSE_BAD_PRINT,
190 // BC_STATUS_PARSE_BAD_FUNC,
191 // BC_STATUS_PARSE_BAD_ASSIGN,
192 // BC_STATUS_PARSE_NO_AUTO,
193 // BC_STATUS_PARSE_DUPLICATE_LOCAL,
194 // BC_STATUS_PARSE_NO_BLOCK_END,
196 // BC_STATUS_MATH_NEGATIVE,
197 // BC_STATUS_MATH_NON_INTEGER,
198 // BC_STATUS_MATH_OVERFLOW,
199 // BC_STATUS_MATH_DIVIDE_BY_ZERO,
200 // BC_STATUS_MATH_BAD_STRING,
202 // BC_STATUS_EXEC_FILE_ERR,
203 // BC_STATUS_EXEC_MISMATCHED_PARAMS,
204 // BC_STATUS_EXEC_UNDEFINED_FUNC,
205 // BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
206 // BC_STATUS_EXEC_NUM_LEN,
207 // BC_STATUS_EXEC_NAME_LEN,
208 // BC_STATUS_EXEC_STRING_LEN,
209 // BC_STATUS_EXEC_ARRAY_LEN,
210 // BC_STATUS_EXEC_BAD_IBASE,
211 // BC_STATUS_EXEC_BAD_SCALE,
212 // BC_STATUS_EXEC_BAD_READ_EXPR,
213 // BC_STATUS_EXEC_REC_READ,
214 // BC_STATUS_EXEC_BAD_TYPE,
215 // BC_STATUS_EXEC_BAD_OBASE,
216 // BC_STATUS_EXEC_SIGNAL,
217 // BC_STATUS_EXEC_STACK,
219 // BC_STATUS_VEC_OUT_OF_BOUNDS,
220 // BC_STATUS_VEC_ITEM_EXISTS,
221 BC_STATUS_BEFORE_POSIX = BC_STATUS_PARSE_EMPTY_EXP,
223 BC_STATUS_POSIX_NAME_LEN,
224 BC_STATUS_POSIX_COMMENT,
225 BC_STATUS_POSIX_BAD_KW,
228 BC_STATUS_POSIX_BOOL,
229 BC_STATUS_POSIX_REL_POS,
230 BC_STATUS_POSIX_MULTIREL,
231 BC_STATUS_POSIX_FOR1,
232 BC_STATUS_POSIX_FOR2,
233 BC_STATUS_POSIX_FOR3,
234 BC_STATUS_POSIX_BRACE,
239 // BC_STATUS_INVALID_OPTION,
241 // Keep enum above and messages below in sync!
242 static const char *const bc_err_msgs[] = {
247 // "memory allocation error",
249 // "file is not text:",
250 // "path is a directory:",
253 // "string end could not be found",
254 // "comment end could not be found",
257 // "extended register",
261 // "bad print statement",
262 // "bad function definition",
263 // "bad assignment: left side must be scale, ibase, "
264 // "obase, last, var, or array element",
265 // "no auto variable found",
266 // "function parameter or auto var has the same name as another",
267 // "block end could not be found",
269 // "negative number",
270 // "non integer number",
273 // "bad number string",
275 // "could not open file:",
276 // "mismatched parameters", // wrong number of them, to be exact
277 // "undefined function",
278 // "file is not executable:",
279 // "number too long: must be [1, BC_NUM_MAX]",
280 // "name too long: must be [1, BC_NAME_MAX]",
281 // "string too long: must be [1, BC_STRING_MAX]",
282 // "array too long; must be [1, BC_DIM_MAX]",
283 // "bad ibase; must be [2, 16]",
284 // "bad scale; must be [0, BC_SCALE_MAX]",
285 // "bad read() expression",
286 // "read() call inside of a read() call",
287 // "variable is wrong type",
288 // "bad obase; must be [2, BC_BASE_MAX]",
289 // "signal caught and not handled",
290 // "stack has too few elements",
292 // "index is out of bounds",
293 // "item already exists",
295 "POSIX only allows one character names; the following is bad:",
296 "POSIX does not allow '#' script comments",
297 "POSIX does not allow the following keyword:",
298 "POSIX does not allow a period ('.') as a shortcut for the last result",
299 "POSIX requires parentheses around return expressions",
300 "POSIX does not allow boolean operators; the following is bad:",
301 "POSIX does not allow comparison operators outside if or loops",
302 "POSIX requires exactly one comparison operator per condition",
303 "POSIX does not allow an empty init expression in a for loop",
304 "POSIX does not allow an empty condition expression in a for loop",
305 "POSIX does not allow an empty update expression in a for loop",
306 "POSIX requires the left brace be on the same line as the function header",
310 #define BC_VEC_INVALID_IDX ((size_t) -1)
311 #define BC_VEC_START_CAP (1 << 5)
313 typedef void (*BcVecFree)(void *);
315 typedef struct BcVec {
323 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
324 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
326 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
328 typedef signed char BcDig;
330 typedef struct BcNum {
338 #define BC_NUM_MIN_BASE ((unsigned long) 2)
339 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
340 #define BC_NUM_DEF_SIZE (16)
341 #define BC_NUM_PRINT_WIDTH (69)
343 #define BC_NUM_KARATSUBA_LEN (32)
345 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
346 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
347 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
348 #define BC_NUM_AREQ(a, b) \
349 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
350 #define BC_NUM_MREQ(a, b, scale) \
351 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
353 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
354 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
356 static void bc_num_init(BcNum *n, size_t req);
357 static void bc_num_expand(BcNum *n, size_t req);
358 static void bc_num_copy(BcNum *d, BcNum *s);
359 static void bc_num_free(void *num);
361 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
362 static void bc_num_ulong2num(BcNum *n, unsigned long val);
364 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
365 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
366 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
367 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
368 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
369 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
370 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
371 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
374 typedef enum BcInst {
404 BC_INST_ASSIGN_POWER,
405 BC_INST_ASSIGN_MULTIPLY,
406 BC_INST_ASSIGN_DIVIDE,
407 BC_INST_ASSIGN_MODULUS,
409 BC_INST_ASSIGN_MINUS,
455 BC_INST_PRINT_STREAM,
470 BC_INST_INVALID = -1,
475 typedef struct BcId {
480 typedef struct BcFunc {
487 typedef enum BcResultType {
492 BC_RESULT_ARRAY_ELEM,
501 // These are between to calculate ibase, obase, and last from instructions.
509 typedef union BcResultData {
515 typedef struct BcResult {
520 typedef struct BcInstPtr {
526 static void bc_array_expand(BcVec *a, size_t len);
527 static int bc_id_cmp(const void *e1, const void *e2);
529 // BC_LEX_NEG is not used in lexing; it is only for parsing.
530 typedef enum BcLexType {
558 BC_LEX_OP_ASSIGN_POWER,
559 BC_LEX_OP_ASSIGN_MULTIPLY,
560 BC_LEX_OP_ASSIGN_DIVIDE,
561 BC_LEX_OP_ASSIGN_MODULUS,
562 BC_LEX_OP_ASSIGN_PLUS,
563 BC_LEX_OP_ASSIGN_MINUS,
637 typedef BcStatus (*BcLexNext)(struct BcLex *);
639 typedef struct BcLex {
658 #define BC_PARSE_STREND ((char) UCHAR_MAX)
660 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
661 #define bc_parse_updateFunc(p, f) \
662 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
664 #define BC_PARSE_REL (1 << 0)
665 #define BC_PARSE_PRINT (1 << 1)
666 #define BC_PARSE_NOCALL (1 << 2)
667 #define BC_PARSE_NOREAD (1 << 3)
668 #define BC_PARSE_ARRAY (1 << 4)
670 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
671 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
673 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
674 #define BC_PARSE_FUNC_INNER(parse) \
675 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
677 #define BC_PARSE_FLAG_FUNC (1 << 1)
678 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
680 #define BC_PARSE_FLAG_BODY (1 << 2)
681 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
683 #define BC_PARSE_FLAG_LOOP (1 << 3)
684 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
686 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
687 #define BC_PARSE_LOOP_INNER(parse) \
688 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
690 #define BC_PARSE_FLAG_IF (1 << 5)
691 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
693 #define BC_PARSE_FLAG_ELSE (1 << 6)
694 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
696 #define BC_PARSE_FLAG_IF_END (1 << 7)
697 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
699 #define BC_PARSE_CAN_EXEC(parse) \
700 (!(BC_PARSE_TOP_FLAG(parse) & \
701 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
702 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
703 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
705 typedef struct BcOp {
710 typedef struct BcParseNext {
715 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
716 #define BC_PARSE_NEXT(a, ...) \
718 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
725 typedef BcStatus (*BcParseParse)(struct BcParse *);
727 typedef struct BcParse {
750 typedef struct BcLexKeyword {
756 #define BC_LEX_KW_ENTRY(a, b, c) \
758 .name = a, .len = (b), .posix = (c) \
761 static BcStatus bc_lex_token(BcLex *l);
763 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
764 #define BC_PARSE_LEAF(p, rparen) \
765 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
766 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
768 // We can calculate the conversion between tokens and exprs by subtracting the
769 // position of the first operator in the lex enum and adding the position of the
770 // first in the expr enum. Note: This only works for binary operators.
771 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
773 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
779 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
781 static BcStatus dc_lex_token(BcLex *l);
783 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
787 typedef struct BcProgram {
828 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
830 #define BC_PROG_MAIN (0)
831 #define BC_PROG_READ (1)
834 #define BC_PROG_REQ_FUNCS (2)
837 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
838 #define BC_PROG_NUM(r, n) \
839 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
841 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
843 static void bc_program_addFunc(char *name, size_t *idx);
844 static void bc_program_reset(void);
846 #define BC_FLAG_X (1 << 0)
847 #define BC_FLAG_W (1 << 1)
848 #define BC_FLAG_V (1 << 2)
849 #define BC_FLAG_S (1 << 3)
850 #define BC_FLAG_Q (1 << 4)
851 #define BC_FLAG_L (1 << 5)
852 #define BC_FLAG_I (1 << 6)
854 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
855 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
857 #define BC_MAX_OBASE ((unsigned) 999)
858 #define BC_MAX_DIM ((unsigned) INT_MAX)
859 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
860 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
861 #define BC_MAX_NAME BC_MAX_STRING
862 #define BC_MAX_NUM BC_MAX_STRING
863 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
864 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
882 #define G (*ptr_to_globals)
883 #define INIT_G() do { \
884 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
886 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
887 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
888 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
889 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
892 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
895 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
899 static void bc_vm_info(void);
901 static const char bc_err_fmt[] = "\nerror: %s\n";
902 static const char bc_warn_fmt[] = "\nwarning: %s\n";
903 static const char bc_err_line[] = ":%zu\n\n";
906 static const BcLexKeyword bc_lex_kws[20] = {
907 BC_LEX_KW_ENTRY("auto", 4, true),
908 BC_LEX_KW_ENTRY("break", 5, true),
909 BC_LEX_KW_ENTRY("continue", 8, false),
910 BC_LEX_KW_ENTRY("define", 6, true),
911 BC_LEX_KW_ENTRY("else", 4, false),
912 BC_LEX_KW_ENTRY("for", 3, true),
913 BC_LEX_KW_ENTRY("halt", 4, false),
914 BC_LEX_KW_ENTRY("ibase", 5, true),
915 BC_LEX_KW_ENTRY("if", 2, true),
916 BC_LEX_KW_ENTRY("last", 4, false),
917 BC_LEX_KW_ENTRY("length", 6, true),
918 BC_LEX_KW_ENTRY("limits", 6, false),
919 BC_LEX_KW_ENTRY("obase", 5, true),
920 BC_LEX_KW_ENTRY("print", 5, false),
921 BC_LEX_KW_ENTRY("quit", 4, true),
922 BC_LEX_KW_ENTRY("read", 4, false),
923 BC_LEX_KW_ENTRY("return", 6, true),
924 BC_LEX_KW_ENTRY("scale", 5, true),
925 BC_LEX_KW_ENTRY("sqrt", 4, true),
926 BC_LEX_KW_ENTRY("while", 5, true),
929 // This is an array that corresponds to token types. An entry is
930 // true if the token is valid in an expression, false otherwise.
931 static const bool bc_parse_exprs[] = {
932 false, false, true, true, true, true, true, true, true, true, true, true,
933 true, true, true, true, true, true, true, true, true, true, true, true,
934 true, true, true, false, false, true, true, false, false, false, false,
935 false, false, false, true, true, false, false, false, false, false, false,
936 false, true, false, true, true, true, true, false, false, true, false, true,
940 // This is an array of data for operators that correspond to token types.
941 static const BcOp bc_parse_ops[] = {
942 { 0, false }, { 0, false },
945 { 3, true }, { 3, true }, { 3, true },
946 { 4, true }, { 4, true },
947 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
949 { 7, true }, { 7, true },
950 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
951 { 5, false }, { 5, false },
954 // These identify what tokens can come after expressions in certain cases.
955 static const BcParseNext bc_parse_next_expr =
956 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
957 static const BcParseNext bc_parse_next_param =
958 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
959 static const BcParseNext bc_parse_next_print =
960 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
961 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
962 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
963 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
964 static const BcParseNext bc_parse_next_read =
965 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
969 static const BcLexType dc_lex_regs[] = {
970 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
971 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
972 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
976 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
978 static const BcLexType dc_lex_tokens[] = {
979 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
980 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
981 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
982 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
983 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
984 BC_LEX_INVALID, BC_LEX_INVALID,
985 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
986 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
987 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
988 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
989 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
990 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
991 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
992 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
993 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
994 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
995 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
996 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
997 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
998 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
999 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1000 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1001 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1002 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1006 static const BcInst dc_parse_insts[] = {
1007 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1008 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1009 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1010 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1011 BC_INST_INVALID, BC_INST_INVALID,
1012 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1013 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1014 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1015 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1016 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1017 BC_INST_INVALID, BC_INST_INVALID,
1018 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1019 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1020 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1021 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1022 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1023 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1024 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1025 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1026 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1027 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1028 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1029 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1033 static const BcNumBinaryOp bc_program_ops[] = {
1034 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1037 static const char bc_program_stdin_name[] = "<stdin>";
1040 static const char *bc_lib_name = "gen/lib.bc";
1042 static const char bc_lib[] = {
1043 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1044 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1045 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1046 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
1047 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1048 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1049 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
1050 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1051 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1052 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
1053 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1054 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1055 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1056 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1057 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1058 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1059 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1060 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1061 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1062 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1063 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1064 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1065 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1066 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
1067 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1068 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
1069 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1070 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1071 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1072 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1073 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1074 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
1075 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1076 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1077 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1078 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1079 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
1080 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1081 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1082 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1083 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1084 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1085 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1086 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1087 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1088 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1089 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1090 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
1091 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
1092 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1093 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
1094 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
1095 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
1096 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1097 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1098 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
1099 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
1100 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
1101 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1102 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
1103 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1104 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1105 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1106 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
1107 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1108 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1109 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1110 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1111 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1112 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1113 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1114 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1115 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1116 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1117 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1118 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1119 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1120 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1121 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1122 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1126 static void fflush_and_check(void)
1129 if (ferror(stdout) || ferror(stderr))
1130 bb_perror_msg_and_die("output error");
1133 static void quit(void) NORETURN;
1134 static void quit(void)
1137 bb_perror_msg_and_die("input error");
1142 static int bc_error(const char *fmt, ...)
1147 bb_verror_msg(fmt, p, NULL);
1151 return BC_STATUS_FAILURE;
1154 static void bc_vec_grow(BcVec *v, size_t n)
1156 size_t cap = v->cap * 2;
1157 while (cap < v->len + n) cap *= 2;
1158 v->v = xrealloc(v->v, v->size * cap);
1162 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1165 v->cap = BC_VEC_START_CAP;
1168 v->v = xmalloc(esize * BC_VEC_START_CAP);
1171 static void bc_vec_expand(BcVec *v, size_t req)
1174 v->v = xrealloc(v->v, v->size * req);
1179 static void bc_vec_npop(BcVec *v, size_t n)
1184 size_t len = v->len - n;
1185 while (v->len > len) v->dtor(v->v + (v->size * --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)
1220 bc_vec_npop(v, v->len);
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;
1255 bc_vec_npop(v, v->len);
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_npop(vec, vec->len);
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)
1392 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1393 G.flags = getopt32long(argv, "xwvsqli",
1394 "extended-register\0" No_argument "x"
1395 "warn\0" No_argument "w"
1396 "version\0" No_argument "v"
1397 "standard\0" No_argument "s"
1398 "quiet\0" No_argument "q"
1399 "mathlib\0" No_argument "l"
1400 "interactive\0" No_argument "i"
1403 G.flags = getopt32(argv, "xwvsqli");
1406 if (G.flags & BC_FLAG_V) bc_vm_info();
1407 // should not be necessary, getopt32() handles this??
1408 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1410 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1413 static void bc_num_setToZero(BcNum *n, size_t scale)
1420 static void bc_num_zero(BcNum *n)
1422 bc_num_setToZero(n, 0);
1425 static void bc_num_one(BcNum *n)
1427 bc_num_setToZero(n, 0);
1432 static void bc_num_ten(BcNum *n)
1434 bc_num_setToZero(n, 0);
1440 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1444 for (i = 0; i < len; ++i) {
1445 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1452 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1456 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1457 return BC_NUM_NEG(i + 1, c < 0);
1460 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1462 size_t i, min, a_int, b_int, diff;
1463 BcDig *max_num, *min_num;
1464 bool a_max, neg = false;
1467 if (a == b) return 0;
1468 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1469 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1479 a_int = BC_NUM_INT(a);
1480 b_int = BC_NUM_INT(b);
1482 a_max = (a->rdx > b->rdx);
1484 if (a_int != 0) return (ssize_t) a_int;
1488 diff = a->rdx - b->rdx;
1489 max_num = a->num + diff;
1494 diff = b->rdx - a->rdx;
1495 max_num = b->num + diff;
1499 cmp = bc_num_compare(max_num, min_num, b_int + min);
1500 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1502 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1503 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1509 static void bc_num_truncate(BcNum *n, size_t places)
1511 if (places == 0) return;
1517 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1521 static void bc_num_extend(BcNum *n, size_t places)
1523 size_t len = n->len + places;
1527 if (n->cap < len) bc_num_expand(n, len);
1529 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1530 memset(n->num, 0, sizeof(BcDig) * places);
1537 static void bc_num_clean(BcNum *n)
1539 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1542 else if (n->len < n->rdx)
1546 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1549 bc_num_extend(n, scale - n->rdx);
1551 bc_num_truncate(n, n->rdx - scale);
1554 if (n->len != 0) n->neg = !neg1 != !neg2;
1557 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1562 b->len = n->len - idx;
1564 a->rdx = b->rdx = 0;
1566 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1567 memcpy(a->num, n->num, idx * sizeof(BcDig));
1578 static BcStatus bc_num_shift(BcNum *n, size_t places)
1580 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1581 if (places + n->len > BC_MAX_NUM)
1582 return bc_error("number too long: must be [1, BC_NUM_MAX]");
1584 if (n->rdx >= places)
1587 bc_num_extend(n, places - n->rdx);
1593 return BC_STATUS_SUCCESS;
1596 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1605 return bc_num_div(&one, a, b, scale);
1608 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1610 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1611 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1614 // Because this function doesn't need to use scale (per the bc spec),
1615 // I am hijacking it to say whether it's doing an add or a subtract.
1619 if (sub && c->len) c->neg = !c->neg;
1620 return BC_STATUS_SUCCESS;
1622 else if (b->len == 0) {
1624 return BC_STATUS_SUCCESS;
1628 c->rdx = BC_MAX(a->rdx, b->rdx);
1629 min_rdx = BC_MIN(a->rdx, b->rdx);
1632 if (a->rdx > b->rdx) {
1633 diff = a->rdx - b->rdx;
1635 ptr_a = a->num + diff;
1639 diff = b->rdx - a->rdx;
1642 ptr_b = b->num + diff;
1645 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1648 a_int = BC_NUM_INT(a);
1649 b_int = BC_NUM_INT(b);
1651 if (a_int > b_int) {
1662 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1663 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1665 ptr_c[i] = (BcDig)(in % 10);
1668 for (; i < max + min_rdx; ++i, ++c->len) {
1669 in = ((int) ptr[i]) + carry;
1671 ptr_c[i] = (BcDig)(in % 10);
1674 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1676 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1679 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1682 BcNum *minuend, *subtrahend;
1684 bool aneg, bneg, neg;
1686 // Because this function doesn't need to use scale (per the bc spec),
1687 // I am hijacking it to say whether it's doing an add or a subtract.
1691 if (sub && c->len) c->neg = !c->neg;
1692 return BC_STATUS_SUCCESS;
1694 else if (b->len == 0) {
1696 return BC_STATUS_SUCCESS;
1701 a->neg = b->neg = false;
1703 cmp = bc_num_cmp(a, b);
1709 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1710 return BC_STATUS_SUCCESS;
1719 if (sub) neg = !neg;
1724 bc_num_copy(c, minuend);
1727 if (c->rdx < subtrahend->rdx) {
1728 bc_num_extend(c, subtrahend->rdx - c->rdx);
1732 start = c->rdx - subtrahend->rdx;
1734 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1738 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1741 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1746 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1747 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1748 bool aone = BC_NUM_ONE(a);
1750 if (a->len == 0 || b->len == 0) {
1752 return BC_STATUS_SUCCESS;
1754 else if (aone || BC_NUM_ONE(b)) {
1755 bc_num_copy(c, aone ? b : a);
1756 return BC_STATUS_SUCCESS;
1759 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1760 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1762 bc_num_expand(c, a->len + b->len + 1);
1764 memset(c->num, 0, sizeof(BcDig) * c->cap);
1765 c->len = carry = len = 0;
1767 for (i = 0; i < b->len; ++i) {
1769 for (j = 0; j < a->len; ++j) {
1770 int in = (int) c->num[i + j];
1771 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1773 c->num[i + j] = (BcDig)(in % 10);
1776 c->num[i + j] += (BcDig) carry;
1777 len = BC_MAX(len, i + j + !!carry);
1783 return BC_STATUS_SUCCESS;
1786 bc_num_init(&l1, max);
1787 bc_num_init(&h1, max);
1788 bc_num_init(&l2, max);
1789 bc_num_init(&h2, max);
1790 bc_num_init(&m1, max);
1791 bc_num_init(&m2, max);
1792 bc_num_init(&z0, max);
1793 bc_num_init(&z1, max);
1794 bc_num_init(&z2, max);
1795 bc_num_init(&temp, max + max);
1797 bc_num_split(a, max2, &l1, &h1);
1798 bc_num_split(b, max2, &l2, &h2);
1800 s = bc_num_add(&h1, &l1, &m1, 0);
1802 s = bc_num_add(&h2, &l2, &m2, 0);
1805 s = bc_num_k(&h1, &h2, &z0);
1807 s = bc_num_k(&m1, &m2, &z1);
1809 s = bc_num_k(&l1, &l2, &z2);
1812 s = bc_num_sub(&z1, &z0, &temp, 0);
1814 s = bc_num_sub(&temp, &z2, &z1, 0);
1817 s = bc_num_shift(&z0, max2 * 2);
1819 s = bc_num_shift(&z1, max2);
1821 s = bc_num_add(&z0, &z1, &temp, 0);
1823 s = bc_num_add(&temp, &z2, c, 0);
1839 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1843 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1845 scale = BC_MAX(scale, a->rdx);
1846 scale = BC_MAX(scale, b->rdx);
1847 scale = BC_MIN(a->rdx + b->rdx, scale);
1848 maxrdx = BC_MAX(maxrdx, scale);
1850 bc_num_init(&cpa, a->len);
1851 bc_num_init(&cpb, b->len);
1853 bc_num_copy(&cpa, a);
1854 bc_num_copy(&cpb, b);
1855 cpa.neg = cpb.neg = false;
1857 s = bc_num_shift(&cpa, maxrdx);
1859 s = bc_num_shift(&cpb, maxrdx);
1861 s = bc_num_k(&cpa, &cpb, c);
1865 bc_num_expand(c, c->len + maxrdx);
1867 if (c->len < maxrdx) {
1868 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1873 bc_num_retireMul(c, scale, a->neg, b->neg);
1881 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1883 BcStatus s = BC_STATUS_SUCCESS;
1890 return bc_error("divide by zero");
1891 else if (a->len == 0) {
1892 bc_num_setToZero(c, scale);
1893 return BC_STATUS_SUCCESS;
1895 else if (BC_NUM_ONE(b)) {
1897 bc_num_retireMul(c, scale, a->neg, b->neg);
1898 return BC_STATUS_SUCCESS;
1901 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1902 bc_num_copy(&cp, a);
1906 bc_num_expand(&cp, len + 2);
1907 bc_num_extend(&cp, len - cp.len);
1910 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1912 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1914 if (b->rdx == b->len) {
1915 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1919 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1921 // We want an extra zero in front to make things simpler.
1922 cp.num[cp.len++] = 0;
1925 bc_num_expand(c, cp.len);
1928 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1933 for (i = end - 1; !s && i < end; --i) {
1935 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1936 bc_num_subArrays(n, p, len);
1940 bc_num_retireMul(c, scale, a->neg, b->neg);
1943 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1946 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1947 BcNum *restrict d, size_t scale, size_t ts)
1954 return bc_error("divide by zero");
1957 bc_num_setToZero(d, ts);
1958 return BC_STATUS_SUCCESS;
1961 bc_num_init(&temp, d->cap);
1962 bc_num_d(a, b, c, scale);
1964 if (scale != 0) scale = ts;
1966 s = bc_num_m(c, b, &temp, scale);
1968 s = bc_num_sub(a, &temp, d, scale);
1971 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1974 bc_num_retireMul(d, ts, a->neg, b->neg);
1982 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1986 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1988 bc_num_init(&c1, len);
1989 s = bc_num_r(a, b, &c1, c, scale, ts);
1995 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1997 BcStatus s = BC_STATUS_SUCCESS;
2000 size_t i, powrdx, resrdx;
2003 if (b->rdx) return bc_error("non integer number");
2007 return BC_STATUS_SUCCESS;
2009 else if (a->len == 0) {
2010 bc_num_setToZero(c, scale);
2011 return BC_STATUS_SUCCESS;
2013 else if (BC_NUM_ONE(b)) {
2017 s = bc_num_inv(a, c, scale);
2024 s = bc_num_ulong(b, &pow);
2027 bc_num_init(©, a->len);
2028 bc_num_copy(©, a);
2030 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2034 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2036 s = bc_num_mul(©, ©, ©, powrdx);
2040 bc_num_copy(c, ©);
2042 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2045 s = bc_num_mul(©, ©, ©, powrdx);
2050 s = bc_num_mul(c, ©, c, resrdx);
2056 s = bc_num_inv(c, c, scale);
2060 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2062 // We can't use bc_num_clean() here.
2063 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2064 if (zero) bc_num_setToZero(c, scale);
2071 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2072 BcNumBinaryOp op, size_t req)
2075 BcNum num2, *ptr_a, *ptr_b;
2080 memcpy(ptr_a, c, sizeof(BcNum));
2089 memcpy(ptr_b, c, sizeof(BcNum));
2097 bc_num_init(c, req);
2099 bc_num_expand(c, req);
2101 s = op(ptr_a, ptr_b, c, scale);
2103 if (init) bc_num_free(&num2);
2108 static bool bc_num_strValid(const char *val, size_t base)
2111 bool small, radix = false;
2112 size_t i, len = strlen(val);
2114 if (!len) return true;
2117 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2119 for (i = 0; i < len; ++i) {
2125 if (radix) return false;
2131 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2138 static void bc_num_parseDecimal(BcNum *n, const char *val)
2144 for (i = 0; val[i] == '0'; ++i);
2151 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2152 bc_num_expand(n, len);
2155 ptr = strchr(val, '.');
2157 // Explicitly test for NULL here to produce either a 0 or 1.
2158 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2161 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2162 n->num[n->len] = val[i] - '0';
2166 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2169 BcNum temp, mult, result;
2173 size_t i, digits, len = strlen(val);
2177 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2180 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2181 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2183 for (i = 0; i < len; ++i) {
2186 if (c == '.') break;
2188 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2190 s = bc_num_mul(n, base, &mult, 0);
2191 if (s) goto int_err;
2192 bc_num_ulong2num(&temp, v);
2193 s = bc_num_add(&mult, &temp, n, 0);
2194 if (s) goto int_err;
2199 if (c == 0) goto int_err;
2202 bc_num_init(&result, base->len);
2203 bc_num_zero(&result);
2206 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2211 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2213 s = bc_num_mul(&result, base, &result, 0);
2215 bc_num_ulong2num(&temp, v);
2216 s = bc_num_add(&result, &temp, &result, 0);
2218 s = bc_num_mul(&mult, base, &mult, 0);
2222 s = bc_num_div(&result, &mult, &result, digits);
2224 s = bc_num_add(n, &result, n, digits);
2228 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2234 bc_num_free(&result);
2240 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2242 if (*nchars == line_len - 1) {
2250 static void bc_num_printChar(size_t num, size_t width, bool radix,
2251 size_t *nchars, size_t line_len)
2253 (void) radix, (void) line_len;
2254 bb_putchar((char) num);
2255 *nchars = *nchars + width;
2259 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2260 size_t *nchars, size_t line_len)
2264 bc_num_printNewline(nchars, line_len);
2265 bb_putchar(radix ? '.' : ' ');
2268 bc_num_printNewline(nchars, line_len);
2269 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2272 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2274 bc_num_printNewline(nchars, line_len);
2277 bb_putchar(((char) dig) + '0');
2281 static void bc_num_printHex(size_t num, size_t width, bool radix,
2282 size_t *nchars, size_t line_len)
2285 bc_num_printNewline(nchars, line_len);
2290 bc_num_printNewline(nchars, line_len);
2291 bb_putchar(bb_hexdigits_upcase[num]);
2292 *nchars = *nchars + width;
2295 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2297 size_t i, rdx = n->rdx - 1;
2299 if (n->neg) bb_putchar('-');
2300 (*nchars) += n->neg;
2302 for (i = n->len - 1; i < n->len; --i)
2303 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2306 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2307 size_t *nchars, size_t len, BcNumDigitOp print)
2311 BcNum intp, fracp, digit, frac_len;
2312 unsigned long dig, *ptr;
2317 print(0, width, false, nchars, len);
2318 return BC_STATUS_SUCCESS;
2321 bc_vec_init(&stack, sizeof(long), NULL);
2322 bc_num_init(&intp, n->len);
2323 bc_num_init(&fracp, n->rdx);
2324 bc_num_init(&digit, width);
2325 bc_num_init(&frac_len, BC_NUM_INT(n));
2326 bc_num_copy(&intp, n);
2327 bc_num_one(&frac_len);
2329 bc_num_truncate(&intp, intp.rdx);
2330 s = bc_num_sub(n, &intp, &fracp, 0);
2333 while (intp.len != 0) {
2334 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2336 s = bc_num_ulong(&digit, &dig);
2338 bc_vec_push(&stack, &dig);
2341 for (i = 0; i < stack.len; ++i) {
2342 ptr = bc_vec_item_rev(&stack, i);
2343 print(*ptr, width, false, nchars, len);
2346 if (!n->rdx) goto err;
2348 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2349 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2351 s = bc_num_ulong(&fracp, &dig);
2353 bc_num_ulong2num(&intp, dig);
2354 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2356 print(dig, width, radix, nchars, len);
2357 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2362 bc_num_free(&frac_len);
2363 bc_num_free(&digit);
2364 bc_num_free(&fracp);
2366 bc_vec_free(&stack);
2370 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2371 size_t *nchars, size_t line_len)
2378 if (neg) bb_putchar('-');
2383 if (base_t <= BC_NUM_MAX_IBASE) {
2385 print = bc_num_printHex;
2388 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2389 print = bc_num_printDigits;
2392 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2399 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2401 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2405 static void bc_num_init(BcNum *n, size_t req)
2407 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2408 memset(n, 0, sizeof(BcNum));
2409 n->num = xmalloc(req);
2413 static void bc_num_expand(BcNum *n, size_t req)
2415 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2417 n->num = xrealloc(n->num, req);
2422 static void bc_num_free(void *num)
2424 free(((BcNum *) num)->num);
2427 static void bc_num_copy(BcNum *d, BcNum *s)
2430 bc_num_expand(d, s->cap);
2434 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2438 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2441 if (!bc_num_strValid(val, base_t))
2442 return bc_error("bad number string");
2445 bc_num_parseDecimal(n, val);
2447 bc_num_parseBase(n, val, base);
2449 return BC_STATUS_SUCCESS;
2452 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2453 size_t *nchars, size_t line_len)
2455 BcStatus s = BC_STATUS_SUCCESS;
2457 bc_num_printNewline(nchars, line_len);
2463 else if (base_t == 10)
2464 bc_num_printDecimal(n, nchars, line_len);
2466 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2476 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2481 if (n->neg) return bc_error("negative number");
2483 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2485 unsigned long prev = *result, powprev = pow;
2487 *result += ((unsigned long) n->num[i]) * pow;
2490 if (*result < prev || pow < powprev)
2491 return bc_error("overflow");
2494 return BC_STATUS_SUCCESS;
2497 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2505 if (val == 0) return;
2507 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2508 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2511 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2513 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2515 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2518 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2520 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2522 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2525 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2527 size_t req = BC_NUM_MREQ(a, b, scale);
2528 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2531 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2533 size_t req = BC_NUM_MREQ(a, b, scale);
2534 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2537 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2539 size_t req = BC_NUM_MREQ(a, b, scale);
2540 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2543 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2545 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2548 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2551 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2552 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2553 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2555 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2556 bc_num_expand(b, req);
2559 bc_num_setToZero(b, scale);
2560 return BC_STATUS_SUCCESS;
2563 return bc_error("negative number");
2564 else if (BC_NUM_ONE(a)) {
2566 bc_num_extend(b, scale);
2567 return BC_STATUS_SUCCESS;
2570 scale = BC_MAX(scale, a->rdx) + 1;
2571 len = a->len + scale;
2573 bc_num_init(&num1, len);
2574 bc_num_init(&num2, len);
2575 bc_num_init(&half, BC_NUM_DEF_SIZE);
2581 bc_num_init(&f, len);
2582 bc_num_init(&fprime, len);
2588 pow = BC_NUM_INT(a);
2597 pow -= 2 - (pow & 1);
2599 bc_num_extend(x0, pow);
2601 // Make sure to move the radix back.
2605 x0->rdx = digs = digs1 = 0;
2607 len = BC_NUM_INT(x0) + resrdx - 1;
2609 while (cmp != 0 || digs < len) {
2611 s = bc_num_div(a, x0, &f, resrdx);
2613 s = bc_num_add(x0, &f, &fprime, resrdx);
2615 s = bc_num_mul(&fprime, &half, x1, resrdx);
2618 cmp = bc_num_cmp(x1, x0);
2619 digs = x1->len - (unsigned long long) llabs(cmp);
2621 if (cmp == cmp2 && digs == digs1)
2626 resrdx += times > 4;
2639 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2642 bc_num_free(&fprime);
2650 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2656 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2659 memcpy(&num2, c, sizeof(BcNum));
2661 bc_num_init(c, len);
2666 bc_num_expand(c, len);
2669 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2671 if (init) bc_num_free(&num2);
2677 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2680 BcNum base, exp, two, temp;
2683 return bc_error("divide by zero");
2684 if (a->rdx || b->rdx || c->rdx)
2685 return bc_error("non integer number");
2687 return bc_error("negative number");
2689 bc_num_expand(d, c->len);
2690 bc_num_init(&base, c->len);
2691 bc_num_init(&exp, b->len);
2692 bc_num_init(&two, BC_NUM_DEF_SIZE);
2693 bc_num_init(&temp, b->len);
2699 s = bc_num_rem(a, c, &base, 0);
2701 bc_num_copy(&exp, b);
2703 while (exp.len != 0) {
2705 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2708 if (BC_NUM_ONE(&temp)) {
2709 s = bc_num_mul(d, &base, &temp, 0);
2711 s = bc_num_rem(&temp, c, d, 0);
2715 s = bc_num_mul(&base, &base, &temp, 0);
2717 s = bc_num_rem(&temp, c, &base, 0);
2730 static int bc_id_cmp(const void *e1, const void *e2)
2732 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2735 static void bc_id_free(void *id)
2737 free(((BcId *) id)->name);
2740 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2745 for (i = 0; i < f->autos.len; ++i) {
2746 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2747 return bc_error("function parameter or auto var has the same name as another");
2753 bc_vec_push(&f->autos, &a);
2755 return BC_STATUS_SUCCESS;
2758 static void bc_func_init(BcFunc *f)
2760 bc_vec_init(&f->code, sizeof(char), NULL);
2761 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2762 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2766 static void bc_func_free(void *func)
2768 BcFunc *f = (BcFunc *) func;
2769 bc_vec_free(&f->code);
2770 bc_vec_free(&f->autos);
2771 bc_vec_free(&f->labels);
2774 static void bc_array_init(BcVec *a, bool nums)
2777 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2779 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2780 bc_array_expand(a, 1);
2783 static void bc_array_copy(BcVec *d, const BcVec *s)
2787 bc_vec_npop(d, d->len);
2788 bc_vec_expand(d, s->cap);
2791 for (i = 0; i < s->len; ++i) {
2792 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2793 bc_num_init(dnum, snum->len);
2794 bc_num_copy(dnum, snum);
2798 static void bc_array_expand(BcVec *a, size_t len)
2802 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2803 while (len > a->len) {
2804 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2805 bc_vec_push(a, &data.n);
2809 while (len > a->len) {
2810 bc_array_init(&data.v, true);
2811 bc_vec_push(a, &data.v);
2816 static void bc_string_free(void *string)
2818 free(*((char **) string));
2822 static void bc_result_copy(BcResult *d, BcResult *src)
2828 case BC_RESULT_TEMP:
2829 case BC_RESULT_IBASE:
2830 case BC_RESULT_SCALE:
2831 case BC_RESULT_OBASE:
2833 bc_num_init(&d->d.n, src->d.n.len);
2834 bc_num_copy(&d->d.n, &src->d.n);
2839 case BC_RESULT_ARRAY:
2840 case BC_RESULT_ARRAY_ELEM:
2842 d->d.id.name = xstrdup(src->d.id.name);
2846 case BC_RESULT_CONSTANT:
2847 case BC_RESULT_LAST:
2851 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2858 static void bc_result_free(void *result)
2860 BcResult *r = (BcResult *) result;
2864 case BC_RESULT_TEMP:
2865 case BC_RESULT_IBASE:
2866 case BC_RESULT_SCALE:
2867 case BC_RESULT_OBASE:
2869 bc_num_free(&r->d.n);
2874 case BC_RESULT_ARRAY:
2875 case BC_RESULT_ARRAY_ELEM:
2889 static void bc_lex_lineComment(BcLex *l)
2891 l->t.t = BC_LEX_WHITESPACE;
2892 while (l->i < l->len && l->buf[l->i++] != '\n');
2896 static void bc_lex_whitespace(BcLex *l)
2899 l->t.t = BC_LEX_WHITESPACE;
2900 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2903 static BcStatus bc_lex_number(BcLex *l, char start)
2905 const char *buf = l->buf + l->i;
2906 size_t len, hits = 0, bslashes = 0, i = 0, j;
2908 bool last_pt, pt = start == '.';
2911 l->t.t = BC_LEX_NUMBER;
2913 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2914 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2928 len = i + 1 * !last_pt - bslashes * 2;
2929 if (len > BC_MAX_NUM)
2930 return bc_error("number too long: must be [1, BC_NUM_MAX]");
2932 bc_vec_npop(&l->t.v, l->t.v.len);
2933 bc_vec_expand(&l->t.v, len + 1);
2934 bc_vec_push(&l->t.v, &start);
2936 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2940 // If we have hit a backslash, skip it. We don't have
2941 // to check for a newline because it's guaranteed.
2942 if (hits < bslashes && c == '\\') {
2948 bc_vec_push(&l->t.v, &c);
2951 bc_vec_pushByte(&l->t.v, '\0');
2954 return BC_STATUS_SUCCESS;
2957 static BcStatus bc_lex_name(BcLex *l)
2960 const char *buf = l->buf + l->i - 1;
2963 l->t.t = BC_LEX_NAME;
2965 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2967 if (i > BC_MAX_STRING)
2968 return bc_error("name too long: must be [1, BC_NAME_MAX]");
2969 bc_vec_string(&l->t.v, i, buf);
2971 // Increment the index. We minus 1 because it has already been incremented.
2974 return BC_STATUS_SUCCESS;
2977 static void bc_lex_init(BcLex *l, BcLexNext next)
2980 bc_vec_init(&l->t.v, sizeof(char), NULL);
2983 static void bc_lex_free(BcLex *l)
2985 bc_vec_free(&l->t.v);
2988 static void bc_lex_file(BcLex *l, const char *file)
2995 static BcStatus bc_lex_next(BcLex *l)
3000 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
3002 l->line += l->newline;
3003 l->t.t = BC_LEX_EOF;
3005 l->newline = (l->i == l->len);
3006 if (l->newline) return BC_STATUS_SUCCESS;
3008 // Loop until failure or we don't have whitespace. This
3009 // is so the parser doesn't get inundated with whitespace.
3012 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3017 static BcStatus bc_lex_text(BcLex *l, const char *text)
3021 l->len = strlen(text);
3022 l->t.t = l->t.last = BC_LEX_INVALID;
3023 return bc_lex_next(l);
3027 static BcStatus bc_lex_identifier(BcLex *l)
3031 const char *buf = l->buf + l->i - 1;
3033 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3035 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3037 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3039 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3041 if (!bc_lex_kws[i].posix) {
3042 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3043 bc_lex_kws[i].name);
3047 // We minus 1 because the index has already been incremented.
3049 return BC_STATUS_SUCCESS;
3056 if (l->t.v.len - 1 > 1)
3057 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3062 static BcStatus bc_lex_string(BcLex *l)
3064 size_t len, nls = 0, i = l->i;
3067 l->t.t = BC_LEX_STR;
3069 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3073 return bc_error("string end could not be found");
3077 if (len > BC_MAX_STRING)
3078 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3079 bc_vec_string(&l->t.v, len, l->buf + l->i);
3084 return BC_STATUS_SUCCESS;
3087 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3089 if (l->buf[l->i] == '=') {
3097 static BcStatus bc_lex_comment(BcLex *l)
3100 const char *buf = l->buf;
3102 l->t.t = BC_LEX_WHITESPACE;
3115 return bc_error("comment end could not be found");
3124 return BC_STATUS_SUCCESS;
3127 static BcStatus bc_lex_token(BcLex *l)
3129 BcStatus s = BC_STATUS_SUCCESS;
3130 char c = l->buf[l->i++], c2;
3132 // This is the workhorse of the lexer.
3139 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3149 bc_lex_whitespace(l);
3155 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3157 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3158 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3167 s = bc_lex_string(l);
3173 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3176 bc_lex_lineComment(l);
3183 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3192 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3196 l->t.t = BC_LEX_OP_BOOL_AND;
3199 l->t.t = BC_LEX_INVALID;
3200 s = bc_error("bad character '%c'", '&');
3209 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3215 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3224 l->t.t = BC_LEX_OP_INC;
3227 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3233 l->t.t = BC_LEX_COMMA;
3242 l->t.t = BC_LEX_OP_DEC;
3245 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3251 if (isdigit(l->buf[l->i]))
3252 s = bc_lex_number(l, c);
3254 l->t.t = BC_LEX_KEY_LAST;
3255 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3264 s = bc_lex_comment(l);
3266 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3287 s = bc_lex_number(l, c);
3293 l->t.t = BC_LEX_SCOLON;
3299 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3305 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3311 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3318 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3324 if (l->buf[l->i] == '\n') {
3325 l->t.t = BC_LEX_WHITESPACE;
3329 s = bc_error("bad character '%c'", c);
3335 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3366 s = bc_lex_identifier(l);
3373 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3383 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3387 l->t.t = BC_LEX_OP_BOOL_OR;
3390 l->t.t = BC_LEX_INVALID;
3391 s = bc_error("bad character '%c'", c);
3399 l->t.t = BC_LEX_INVALID;
3400 s = bc_error("bad character '%c'", c);
3410 static BcStatus dc_lex_register(BcLex *l)
3412 BcStatus s = BC_STATUS_SUCCESS;
3414 if (isspace(l->buf[l->i - 1])) {
3415 bc_lex_whitespace(l);
3418 s = bc_error("extended register");
3423 bc_vec_npop(&l->t.v, l->t.v.len);
3424 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3425 bc_vec_pushByte(&l->t.v, '\0');
3426 l->t.t = BC_LEX_NAME;
3432 static BcStatus dc_lex_string(BcLex *l)
3434 size_t depth = 1, nls = 0, i = l->i;
3437 l->t.t = BC_LEX_STR;
3438 bc_vec_npop(&l->t.v, l->t.v.len);
3440 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3442 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3443 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3446 if (depth) bc_vec_push(&l->t.v, &c);
3451 return bc_error("string end could not be found");
3454 bc_vec_pushByte(&l->t.v, '\0');
3455 if (i - l->i > BC_MAX_STRING)
3456 return bc_error("string too long: must be [1, BC_STRING_MAX]");
3461 return BC_STATUS_SUCCESS;
3464 static BcStatus dc_lex_token(BcLex *l)
3466 BcStatus s = BC_STATUS_SUCCESS;
3467 char c = l->buf[l->i++], c2;
3470 for (i = 0; i < dc_lex_regs_len; ++i) {
3471 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3474 if (c >= '%' && c <= '~' &&
3475 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3480 // This is the workhorse of the lexer.
3485 l->t.t = BC_LEX_EOF;
3496 l->newline = (c == '\n');
3497 bc_lex_whitespace(l);
3506 l->t.t = BC_LEX_OP_REL_NE;
3508 l->t.t = BC_LEX_OP_REL_LE;
3510 l->t.t = BC_LEX_OP_REL_GE;
3512 return bc_error("bad character '%c'", c);
3520 bc_lex_lineComment(l);
3526 if (isdigit(l->buf[l->i]))
3527 s = bc_lex_number(l, c);
3529 s = bc_error("bad character '%c'", c);
3550 s = bc_lex_number(l, c);
3556 s = dc_lex_string(l);
3562 l->t.t = BC_LEX_INVALID;
3563 s = bc_error("bad character '%c'", c);
3572 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3574 bc_program_addFunc(name, idx);
3575 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3578 static void bc_parse_pushName(BcParse *p, char *name)
3580 size_t i = 0, len = strlen(name);
3582 for (; i < len; ++i) bc_parse_push(p, name[i]);
3583 bc_parse_push(p, BC_PARSE_STREND);
3588 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3590 unsigned char amt, i, nums[sizeof(size_t)];
3592 for (amt = 0; idx; ++amt) {
3593 nums[amt] = (char) idx;
3594 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3597 bc_parse_push(p, amt);
3598 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3601 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3603 char *num = xstrdup(p->l.t.v.v);
3604 size_t idx = G.prog.consts.len;
3606 bc_vec_push(&G.prog.consts, &num);
3608 bc_parse_push(p, BC_INST_NUM);
3609 bc_parse_pushIndex(p, idx);
3612 (*prev) = BC_INST_NUM;
3615 static BcStatus bc_parse_text(BcParse *p, const char *text)
3619 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3621 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
3622 p->l.t.t = BC_LEX_INVALID;
3625 if (!BC_PARSE_CAN_EXEC(p))
3626 return bc_error("file is not executable");
3629 return bc_lex_text(&p->l, text);
3632 // Called when bc/dc_parse_parse() detects a failure,
3633 // resets parsing structures.
3634 static void bc_parse_reset(BcParse *p)
3636 if (p->fidx != BC_PROG_MAIN) {
3638 p->func->nparams = 0;
3639 bc_vec_npop(&p->func->code, p->func->code.len);
3640 bc_vec_npop(&p->func->autos, p->func->autos.len);
3641 bc_vec_npop(&p->func->labels, p->func->labels.len);
3643 bc_parse_updateFunc(p, BC_PROG_MAIN);
3647 p->l.t.t = BC_LEX_EOF;
3648 p->auto_part = (p->nbraces = 0);
3650 bc_vec_npop(&p->flags, p->flags.len - 1);
3651 bc_vec_npop(&p->exits, p->exits.len);
3652 bc_vec_npop(&p->conds, p->conds.len);
3653 bc_vec_npop(&p->ops, p->ops.len);
3658 static void bc_parse_free(BcParse *p)
3660 bc_vec_free(&p->flags);
3661 bc_vec_free(&p->exits);
3662 bc_vec_free(&p->conds);
3663 bc_vec_free(&p->ops);
3667 static void bc_parse_create(BcParse *p, size_t func,
3668 BcParseParse parse, BcLexNext next)
3670 memset(p, 0, sizeof(BcParse));
3672 bc_lex_init(&p->l, next);
3673 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3674 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3675 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3676 bc_vec_pushByte(&p->flags, 0);
3677 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3680 // p->auto_part = p->nbraces = 0; - already is
3681 bc_parse_updateFunc(p, func);
3685 static BcStatus bc_parse_else(BcParse *p);
3686 static BcStatus bc_parse_stmt(BcParse *p);
3688 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3689 size_t *nexprs, bool next)
3691 BcStatus s = BC_STATUS_SUCCESS;
3693 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3694 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3696 while (p->ops.len > start) {
3698 t = BC_PARSE_TOP_OP(p);
3699 if (t == BC_LEX_LPAREN) break;
3701 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3702 if (l >= r && (l != r || !left)) break;
3704 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3705 bc_vec_pop(&p->ops);
3706 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3709 bc_vec_push(&p->ops, &type);
3710 if (next) s = bc_lex_next(&p->l);
3715 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3719 if (p->ops.len <= ops_bgn)
3720 return bc_error("bad expression");
3721 top = BC_PARSE_TOP_OP(p);
3723 while (top != BC_LEX_LPAREN) {
3725 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3727 bc_vec_pop(&p->ops);
3728 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3730 if (p->ops.len <= ops_bgn)
3731 return bc_error("bad expression");
3732 top = BC_PARSE_TOP_OP(p);
3735 bc_vec_pop(&p->ops);
3737 return bc_lex_next(&p->l);
3740 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3746 s = bc_lex_next(&p->l);
3749 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3751 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3752 s = bc_parse_expr(p, flags, bc_parse_next_param);
3755 comma = p->l.t.t == BC_LEX_COMMA;
3757 s = bc_lex_next(&p->l);
3762 if (comma) return bc_error("bad token");
3763 bc_parse_push(p, BC_INST_CALL);
3764 bc_parse_pushIndex(p, nparams);
3766 return BC_STATUS_SUCCESS;
3769 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3772 BcId entry, *entry_ptr;
3777 s = bc_parse_params(p, flags);
3780 if (p->l.t.t != BC_LEX_RPAREN) {
3781 s = bc_error("bad token");
3785 idx = bc_map_index(&G.prog.fn_map, &entry);
3787 if (idx == BC_VEC_INVALID_IDX) {
3788 name = xstrdup(entry.name);
3789 bc_parse_addFunc(p, name, &idx);
3790 idx = bc_map_index(&G.prog.fn_map, &entry);
3796 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3797 bc_parse_pushIndex(p, entry_ptr->idx);
3799 return bc_lex_next(&p->l);
3806 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3811 name = xstrdup(p->l.t.v.v);
3812 s = bc_lex_next(&p->l);
3815 if (p->l.t.t == BC_LEX_LBRACKET) {
3817 s = bc_lex_next(&p->l);
3820 if (p->l.t.t == BC_LEX_RBRACKET) {
3822 if (!(flags & BC_PARSE_ARRAY)) {
3823 s = bc_error("bad expression");
3827 *type = BC_INST_ARRAY;
3831 *type = BC_INST_ARRAY_ELEM;
3833 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3834 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3838 s = bc_lex_next(&p->l);
3840 bc_parse_push(p, *type);
3841 bc_parse_pushName(p, name);
3843 else if (p->l.t.t == BC_LEX_LPAREN) {
3845 if (flags & BC_PARSE_NOCALL) {
3846 s = bc_error("bad token");
3850 *type = BC_INST_CALL;
3851 s = bc_parse_call(p, name, flags);
3854 *type = BC_INST_VAR;
3855 bc_parse_push(p, BC_INST_VAR);
3856 bc_parse_pushName(p, name);
3866 static BcStatus bc_parse_read(BcParse *p)
3870 s = bc_lex_next(&p->l);
3872 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3874 s = bc_lex_next(&p->l);
3876 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3878 bc_parse_push(p, BC_INST_READ);
3880 return bc_lex_next(&p->l);
3883 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3888 s = bc_lex_next(&p->l);
3890 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
3892 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3894 s = bc_lex_next(&p->l);
3897 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3900 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3902 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3903 bc_parse_push(p, *prev);
3905 return bc_lex_next(&p->l);
3908 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3912 s = bc_lex_next(&p->l);
3915 if (p->l.t.t != BC_LEX_LPAREN) {
3916 *type = BC_INST_SCALE;
3917 bc_parse_push(p, BC_INST_SCALE);
3918 return BC_STATUS_SUCCESS;
3921 *type = BC_INST_SCALE_FUNC;
3922 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3924 s = bc_lex_next(&p->l);
3927 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3929 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
3930 bc_parse_push(p, BC_INST_SCALE_FUNC);
3932 return bc_lex_next(&p->l);
3935 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3936 size_t *nexprs, uint8_t flags)
3941 BcInst etype = *prev;
3943 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3944 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3945 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3947 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3948 bc_parse_push(p, inst);
3949 s = bc_lex_next(&p->l);
3953 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3956 s = bc_lex_next(&p->l);
3960 // Because we parse the next part of the expression
3961 // right here, we need to increment this.
3962 *nexprs = *nexprs + 1;
3968 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3972 case BC_LEX_KEY_IBASE:
3973 case BC_LEX_KEY_LAST:
3974 case BC_LEX_KEY_OBASE:
3976 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3977 s = bc_lex_next(&p->l);
3981 case BC_LEX_KEY_SCALE:
3983 s = bc_lex_next(&p->l);
3985 if (p->l.t.t == BC_LEX_LPAREN)
3986 s = bc_error("bad token");
3988 bc_parse_push(p, BC_INST_SCALE);
3994 s = bc_error("bad token");
3999 if (!s) bc_parse_push(p, inst);
4005 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4006 bool rparen, size_t *nexprs)
4010 BcInst etype = *prev;
4012 s = bc_lex_next(&p->l);
4015 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4016 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4019 *prev = BC_PARSE_TOKEN_INST(type);
4021 // We can just push onto the op stack because this is the largest
4022 // precedence operator that gets pushed. Inc/dec does not.
4023 if (type != BC_LEX_OP_MINUS)
4024 bc_vec_push(&p->ops, &type);
4026 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4031 static BcStatus bc_parse_string(BcParse *p, char inst)
4033 char *str = xstrdup(p->l.t.v.v);
4035 bc_parse_push(p, BC_INST_STR);
4036 bc_parse_pushIndex(p, G.prog.strs.len);
4037 bc_vec_push(&G.prog.strs, &str);
4038 bc_parse_push(p, inst);
4040 return bc_lex_next(&p->l);
4043 static BcStatus bc_parse_print(BcParse *p)
4049 s = bc_lex_next(&p->l);
4054 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4055 return bc_error("bad print statement");
4057 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4059 if (type == BC_LEX_STR)
4060 s = bc_parse_string(p, BC_INST_PRINT_POP);
4062 s = bc_parse_expr(p, 0, bc_parse_next_print);
4064 bc_parse_push(p, BC_INST_PRINT_POP);
4069 comma = p->l.t.t == BC_LEX_COMMA;
4070 if (comma) s = bc_lex_next(&p->l);
4075 if (comma) return bc_error("bad token");
4077 return bc_lex_next(&p->l);
4080 static BcStatus bc_parse_return(BcParse *p)
4086 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
4088 s = bc_lex_next(&p->l);
4092 paren = t == BC_LEX_LPAREN;
4094 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4095 bc_parse_push(p, BC_INST_RET0);
4098 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4099 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4102 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4103 bc_parse_push(p, BC_INST_RET0);
4104 s = bc_lex_next(&p->l);
4108 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4109 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4113 bc_parse_push(p, BC_INST_RET);
4119 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4121 BcStatus s = BC_STATUS_SUCCESS;
4123 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4124 return bc_error("bad token");
4128 if (p->l.t.t == BC_LEX_RBRACE) {
4129 if (!p->nbraces) return bc_error("bad token");
4131 s = bc_lex_next(&p->l);
4135 return bc_error("bad token");
4138 if (BC_PARSE_IF(p)) {
4142 while (p->l.t.t == BC_LEX_NLINE) {
4143 s = bc_lex_next(&p->l);
4147 bc_vec_pop(&p->flags);
4149 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4150 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4152 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4154 else if (BC_PARSE_ELSE(p)) {
4159 bc_vec_pop(&p->flags);
4161 ip = bc_vec_top(&p->exits);
4162 label = bc_vec_item(&p->func->labels, ip->idx);
4163 *label = p->func->code.len;
4165 bc_vec_pop(&p->exits);
4167 else if (BC_PARSE_FUNC_INNER(p)) {
4168 bc_parse_push(p, BC_INST_RET0);
4169 bc_parse_updateFunc(p, BC_PROG_MAIN);
4170 bc_vec_pop(&p->flags);
4174 BcInstPtr *ip = bc_vec_top(&p->exits);
4175 size_t *label = bc_vec_top(&p->conds);
4177 bc_parse_push(p, BC_INST_JUMP);
4178 bc_parse_pushIndex(p, *label);
4180 label = bc_vec_item(&p->func->labels, ip->idx);
4181 *label = p->func->code.len;
4183 bc_vec_pop(&p->flags);
4184 bc_vec_pop(&p->exits);
4185 bc_vec_pop(&p->conds);
4191 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4193 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4194 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4195 flags |= BC_PARSE_FLAG_BODY;
4196 bc_vec_push(&p->flags, &flags);
4199 static void bc_parse_noElse(BcParse *p)
4203 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4205 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4207 ip = bc_vec_top(&p->exits);
4208 label = bc_vec_item(&p->func->labels, ip->idx);
4209 *label = p->func->code.len;
4211 bc_vec_pop(&p->exits);
4214 static BcStatus bc_parse_if(BcParse *p)
4219 s = bc_lex_next(&p->l);
4221 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4223 s = bc_lex_next(&p->l);
4225 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4227 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4229 s = bc_lex_next(&p->l);
4231 bc_parse_push(p, BC_INST_JUMP_ZERO);
4233 ip.idx = p->func->labels.len;
4234 ip.func = ip.len = 0;
4236 bc_parse_pushIndex(p, ip.idx);
4237 bc_vec_push(&p->exits, &ip);
4238 bc_vec_push(&p->func->labels, &ip.idx);
4239 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4241 return BC_STATUS_SUCCESS;
4244 static BcStatus bc_parse_else(BcParse *p)
4248 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
4250 ip.idx = p->func->labels.len;
4251 ip.func = ip.len = 0;
4253 bc_parse_push(p, BC_INST_JUMP);
4254 bc_parse_pushIndex(p, ip.idx);
4258 bc_vec_push(&p->exits, &ip);
4259 bc_vec_push(&p->func->labels, &ip.idx);
4260 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4262 return bc_lex_next(&p->l);
4265 static BcStatus bc_parse_while(BcParse *p)
4270 s = bc_lex_next(&p->l);
4272 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4273 s = bc_lex_next(&p->l);
4276 ip.idx = p->func->labels.len;
4278 bc_vec_push(&p->func->labels, &p->func->code.len);
4279 bc_vec_push(&p->conds, &ip.idx);
4281 ip.idx = p->func->labels.len;
4285 bc_vec_push(&p->exits, &ip);
4286 bc_vec_push(&p->func->labels, &ip.idx);
4288 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4290 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4291 s = bc_lex_next(&p->l);
4294 bc_parse_push(p, BC_INST_JUMP_ZERO);
4295 bc_parse_pushIndex(p, ip.idx);
4296 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4298 return BC_STATUS_SUCCESS;
4301 static BcStatus bc_parse_for(BcParse *p)
4305 size_t cond_idx, exit_idx, body_idx, update_idx;
4307 s = bc_lex_next(&p->l);
4309 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
4310 s = bc_lex_next(&p->l);
4313 if (p->l.t.t != BC_LEX_SCOLON)
4314 s = bc_parse_expr(p, 0, bc_parse_next_for);
4316 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4319 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4320 s = bc_lex_next(&p->l);
4323 cond_idx = p->func->labels.len;
4324 update_idx = cond_idx + 1;
4325 body_idx = update_idx + 1;
4326 exit_idx = body_idx + 1;
4328 bc_vec_push(&p->func->labels, &p->func->code.len);
4330 if (p->l.t.t != BC_LEX_SCOLON)
4331 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4333 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4336 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
4338 s = bc_lex_next(&p->l);
4341 bc_parse_push(p, BC_INST_JUMP_ZERO);
4342 bc_parse_pushIndex(p, exit_idx);
4343 bc_parse_push(p, BC_INST_JUMP);
4344 bc_parse_pushIndex(p, body_idx);
4346 ip.idx = p->func->labels.len;
4348 bc_vec_push(&p->conds, &update_idx);
4349 bc_vec_push(&p->func->labels, &p->func->code.len);
4351 if (p->l.t.t != BC_LEX_RPAREN)
4352 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4354 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4358 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
4359 bc_parse_push(p, BC_INST_JUMP);
4360 bc_parse_pushIndex(p, cond_idx);
4361 bc_vec_push(&p->func->labels, &p->func->code.len);
4367 bc_vec_push(&p->exits, &ip);
4368 bc_vec_push(&p->func->labels, &ip.idx);
4370 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4372 return BC_STATUS_SUCCESS;
4375 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4381 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
4383 if (type == BC_LEX_KEY_BREAK) {
4385 if (p->exits.len == 0) return bc_error("bad token");
4387 i = p->exits.len - 1;
4388 ip = bc_vec_item(&p->exits, i);
4390 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4391 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
4396 i = *((size_t *) bc_vec_top(&p->conds));
4398 bc_parse_push(p, BC_INST_JUMP);
4399 bc_parse_pushIndex(p, i);
4401 s = bc_lex_next(&p->l);
4404 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4405 return bc_error("bad token");
4407 return bc_lex_next(&p->l);
4410 static BcStatus bc_parse_func(BcParse *p)
4413 bool var, comma = false;
4417 s = bc_lex_next(&p->l);
4419 if (p->l.t.t != BC_LEX_NAME)
4420 return bc_error("bad function definition");
4422 name = xstrdup(p->l.t.v.v);
4423 bc_parse_addFunc(p, name, &p->fidx);
4425 s = bc_lex_next(&p->l);
4427 if (p->l.t.t != BC_LEX_LPAREN)
4428 return bc_error("bad function definition");
4429 s = bc_lex_next(&p->l);
4432 while (p->l.t.t != BC_LEX_RPAREN) {
4434 if (p->l.t.t != BC_LEX_NAME)
4435 return bc_error("bad function definition");
4439 name = xstrdup(p->l.t.v.v);
4440 s = bc_lex_next(&p->l);
4443 var = p->l.t.t != BC_LEX_LBRACKET;
4447 s = bc_lex_next(&p->l);
4450 if (p->l.t.t != BC_LEX_RBRACKET) {
4451 s = bc_error("bad function definition");
4455 s = bc_lex_next(&p->l);
4459 comma = p->l.t.t == BC_LEX_COMMA;
4461 s = bc_lex_next(&p->l);
4465 s = bc_func_insert(p->func, name, var);
4469 if (comma) return bc_error("bad function definition");
4471 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4472 bc_parse_startBody(p, flags);
4474 s = bc_lex_next(&p->l);
4477 if (p->l.t.t != BC_LEX_LBRACE)
4478 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4487 static BcStatus bc_parse_auto(BcParse *p)
4490 bool comma, var, one;
4493 if (!p->auto_part) return bc_error("bad token");
4494 s = bc_lex_next(&p->l);
4497 p->auto_part = comma = false;
4498 one = p->l.t.t == BC_LEX_NAME;
4500 while (p->l.t.t == BC_LEX_NAME) {
4502 name = xstrdup(p->l.t.v.v);
4503 s = bc_lex_next(&p->l);
4506 var = p->l.t.t != BC_LEX_LBRACKET;
4509 s = bc_lex_next(&p->l);
4512 if (p->l.t.t != BC_LEX_RBRACKET) {
4513 s = bc_error("bad function definition");
4517 s = bc_lex_next(&p->l);
4521 comma = p->l.t.t == BC_LEX_COMMA;
4523 s = bc_lex_next(&p->l);
4527 s = bc_func_insert(p->func, name, var);
4531 if (comma) return bc_error("bad function definition");
4532 if (!one) return bc_error("no auto variable found");
4534 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4535 return bc_error("bad token");
4537 return bc_lex_next(&p->l);
4544 static BcStatus bc_parse_body(BcParse *p, bool brace)
4546 BcStatus s = BC_STATUS_SUCCESS;
4547 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4549 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4551 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4553 if (!brace) return bc_error("bad token");
4554 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4556 if (!p->auto_part) {
4557 s = bc_parse_auto(p);
4561 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4564 s = bc_parse_stmt(p);
4565 if (!s && !brace) s = bc_parse_endBody(p, false);
4571 static BcStatus bc_parse_stmt(BcParse *p)
4573 BcStatus s = BC_STATUS_SUCCESS;
4579 return bc_lex_next(&p->l);
4582 case BC_LEX_KEY_ELSE:
4584 p->auto_part = false;
4590 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
4593 s = bc_lex_next(&p->l);
4596 return bc_parse_body(p, true);
4599 case BC_LEX_KEY_AUTO:
4601 return bc_parse_auto(p);
4606 p->auto_part = false;
4608 if (BC_PARSE_IF_END(p)) {
4610 return BC_STATUS_SUCCESS;
4612 else if (BC_PARSE_BODY(p))
4613 return bc_parse_body(p, false);
4623 case BC_LEX_OP_MINUS:
4624 case BC_LEX_OP_BOOL_NOT:
4628 case BC_LEX_KEY_IBASE:
4629 case BC_LEX_KEY_LAST:
4630 case BC_LEX_KEY_LENGTH:
4631 case BC_LEX_KEY_OBASE:
4632 case BC_LEX_KEY_READ:
4633 case BC_LEX_KEY_SCALE:
4634 case BC_LEX_KEY_SQRT:
4636 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4640 case BC_LEX_KEY_ELSE:
4642 s = bc_parse_else(p);
4648 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4654 s = bc_parse_endBody(p, true);
4660 s = bc_parse_string(p, BC_INST_PRINT_STR);
4664 case BC_LEX_KEY_BREAK:
4665 case BC_LEX_KEY_CONTINUE:
4667 s = bc_parse_loopExit(p, p->l.t.t);
4671 case BC_LEX_KEY_FOR:
4673 s = bc_parse_for(p);
4677 case BC_LEX_KEY_HALT:
4679 bc_parse_push(p, BC_INST_HALT);
4680 s = bc_lex_next(&p->l);
4690 case BC_LEX_KEY_LIMITS:
4692 // "limits" is a compile-time command,
4693 // the output is produced at _parse time_.
4694 s = bc_lex_next(&p->l);
4696 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4697 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4698 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4699 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4700 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4701 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4702 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4703 printf("Number of vars = %lu\n", BC_MAX_VARS);
4707 case BC_LEX_KEY_PRINT:
4709 s = bc_parse_print(p);
4713 case BC_LEX_KEY_QUIT:
4715 // "quit" is a compile-time command. For example,
4716 // "if (0 == 1) quit" terminates when parsing the statement,
4717 // not when it is executed
4721 case BC_LEX_KEY_RETURN:
4723 s = bc_parse_return(p);
4727 case BC_LEX_KEY_WHILE:
4729 s = bc_parse_while(p);
4735 s = bc_error("bad token");
4743 static BcStatus bc_parse_parse(BcParse *p)
4747 if (p->l.t.t == BC_LEX_EOF)
4748 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
4749 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4750 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
4751 s = bc_parse_func(p);
4754 s = bc_parse_stmt(p);
4756 if (s || G_interrupt) {
4758 s = BC_STATUS_FAILURE;
4764 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4766 BcStatus s = BC_STATUS_SUCCESS;
4767 BcInst prev = BC_INST_PRINT;
4768 BcLexType top, t = p->l.t.t;
4769 size_t nexprs = 0, ops_bgn = p->ops.len;
4770 uint32_t i, nparens, nrelops;
4771 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4773 paren_first = p->l.t.t == BC_LEX_LPAREN;
4774 nparens = nrelops = 0;
4775 paren_expr = rprn = done = get_token = assign = false;
4778 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4784 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4785 rprn = get_token = bin_last = false;
4789 case BC_LEX_OP_MINUS:
4791 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4792 rprn = get_token = false;
4793 bin_last = prev == BC_INST_MINUS;
4797 case BC_LEX_OP_ASSIGN_POWER:
4798 case BC_LEX_OP_ASSIGN_MULTIPLY:
4799 case BC_LEX_OP_ASSIGN_DIVIDE:
4800 case BC_LEX_OP_ASSIGN_MODULUS:
4801 case BC_LEX_OP_ASSIGN_PLUS:
4802 case BC_LEX_OP_ASSIGN_MINUS:
4803 case BC_LEX_OP_ASSIGN:
4805 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4806 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4807 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4809 s = bc_error("bad assignment:"
4810 " left side must be scale,"
4811 " ibase, obase, last, var,"
4818 case BC_LEX_OP_POWER:
4819 case BC_LEX_OP_MULTIPLY:
4820 case BC_LEX_OP_DIVIDE:
4821 case BC_LEX_OP_MODULUS:
4822 case BC_LEX_OP_PLUS:
4823 case BC_LEX_OP_REL_EQ:
4824 case BC_LEX_OP_REL_LE:
4825 case BC_LEX_OP_REL_GE:
4826 case BC_LEX_OP_REL_NE:
4827 case BC_LEX_OP_REL_LT:
4828 case BC_LEX_OP_REL_GT:
4829 case BC_LEX_OP_BOOL_NOT:
4830 case BC_LEX_OP_BOOL_OR:
4831 case BC_LEX_OP_BOOL_AND:
4833 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4834 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4836 return bc_error("bad expression");
4839 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4840 prev = BC_PARSE_TOKEN_INST(t);
4841 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4842 rprn = get_token = false;
4843 bin_last = t != BC_LEX_OP_BOOL_NOT;
4850 if (BC_PARSE_LEAF(prev, rprn))
4851 return bc_error("bad expression");
4853 paren_expr = rprn = bin_last = false;
4855 bc_vec_push(&p->ops, &t);
4862 if (bin_last || prev == BC_INST_BOOL_NOT)
4863 return bc_error("bad expression");
4866 s = BC_STATUS_SUCCESS;
4871 else if (!paren_expr)
4872 return BC_STATUS_PARSE_EMPTY_EXP;
4875 paren_expr = rprn = true;
4876 get_token = bin_last = false;
4878 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4885 if (BC_PARSE_LEAF(prev, rprn))
4886 return bc_error("bad expression");
4888 rprn = get_token = bin_last = false;
4889 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4897 if (BC_PARSE_LEAF(prev, rprn))
4898 return bc_error("bad expression");
4899 bc_parse_number(p, &prev, &nexprs);
4900 paren_expr = get_token = true;
4901 rprn = bin_last = false;
4906 case BC_LEX_KEY_IBASE:
4907 case BC_LEX_KEY_LAST:
4908 case BC_LEX_KEY_OBASE:
4910 if (BC_PARSE_LEAF(prev, rprn))
4911 return bc_error("bad expression");
4912 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4913 bc_parse_push(p, (char) prev);
4915 paren_expr = get_token = true;
4916 rprn = bin_last = false;
4922 case BC_LEX_KEY_LENGTH:
4923 case BC_LEX_KEY_SQRT:
4925 if (BC_PARSE_LEAF(prev, rprn))
4926 return bc_error("bad expression");
4927 s = bc_parse_builtin(p, t, flags, &prev);
4929 rprn = get_token = bin_last = false;
4935 case BC_LEX_KEY_READ:
4937 if (BC_PARSE_LEAF(prev, rprn))
4938 return bc_error("bad expression");
4939 else if (flags & BC_PARSE_NOREAD)
4940 s = bc_error("read() call inside of a read() call");
4942 s = bc_parse_read(p);
4945 rprn = get_token = bin_last = false;
4947 prev = BC_INST_READ;
4952 case BC_LEX_KEY_SCALE:
4954 if (BC_PARSE_LEAF(prev, rprn))
4955 return bc_error("bad expression");
4956 s = bc_parse_scale(p, &prev, flags);
4958 rprn = get_token = bin_last = false;
4960 prev = BC_INST_SCALE;
4967 s = bc_error("bad token");
4972 if (!s && get_token) s = bc_lex_next(&p->l);
4976 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4978 while (p->ops.len > ops_bgn) {
4980 top = BC_PARSE_TOP_OP(p);
4981 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4983 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4984 return bc_error("bad expression");
4986 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4988 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4989 bc_vec_pop(&p->ops);
4992 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4993 return bc_error("bad expression");
4995 for (i = 0; i < next.len; ++i)
4996 if (t == next.tokens[i])
4998 return bc_error("bad expression");
5001 if (!(flags & BC_PARSE_REL) && nrelops) {
5002 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5005 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5006 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5010 if (flags & BC_PARSE_PRINT) {
5011 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5012 bc_parse_push(p, BC_INST_POP);
5018 static void bc_parse_init(BcParse *p, size_t func)
5020 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
5023 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5025 return bc_parse_expr(p, flags, bc_parse_next_read);
5030 static BcStatus dc_parse_register(BcParse *p)
5035 s = bc_lex_next(&p->l);
5037 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
5039 name = xstrdup(p->l.t.v.v);
5040 bc_parse_pushName(p, name);
5045 static BcStatus dc_parse_string(BcParse *p)
5047 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5048 size_t idx, len = G.prog.strs.len;
5050 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5053 str = xstrdup(p->l.t.v.v);
5054 bc_parse_push(p, BC_INST_STR);
5055 bc_parse_pushIndex(p, len);
5056 bc_vec_push(&G.prog.strs, &str);
5057 bc_parse_addFunc(p, name, &idx);
5059 return bc_lex_next(&p->l);
5062 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5066 bc_parse_push(p, inst);
5068 s = dc_parse_register(p);
5073 bc_parse_push(p, BC_INST_SWAP);
5074 bc_parse_push(p, BC_INST_ASSIGN);
5075 bc_parse_push(p, BC_INST_POP);
5078 return bc_lex_next(&p->l);
5081 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5085 bc_parse_push(p, inst);
5086 bc_parse_push(p, BC_INST_EXEC_COND);
5088 s = dc_parse_register(p);
5091 s = bc_lex_next(&p->l);
5094 if (p->l.t.t == BC_LEX_ELSE) {
5095 s = dc_parse_register(p);
5097 s = bc_lex_next(&p->l);
5100 bc_parse_push(p, BC_PARSE_STREND);
5105 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5107 BcStatus s = BC_STATUS_SUCCESS;
5110 bool assign, get_token = false;
5114 case BC_LEX_OP_REL_EQ:
5115 case BC_LEX_OP_REL_LE:
5116 case BC_LEX_OP_REL_GE:
5117 case BC_LEX_OP_REL_NE:
5118 case BC_LEX_OP_REL_LT:
5119 case BC_LEX_OP_REL_GT:
5121 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5128 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5134 s = dc_parse_string(p);
5141 if (t == BC_LEX_NEG) {
5142 s = bc_lex_next(&p->l);
5144 if (p->l.t.t != BC_LEX_NUMBER)
5145 return bc_error("bad token");
5148 bc_parse_number(p, &prev, &p->nbraces);
5150 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5156 case BC_LEX_KEY_READ:
5158 if (flags & BC_PARSE_NOREAD)
5159 s = bc_error("read() call inside of a read() call");
5161 bc_parse_push(p, BC_INST_READ);
5166 case BC_LEX_OP_ASSIGN:
5167 case BC_LEX_STORE_PUSH:
5169 assign = t == BC_LEX_OP_ASSIGN;
5170 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5171 s = dc_parse_mem(p, inst, true, assign);
5176 case BC_LEX_LOAD_POP:
5178 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5179 s = dc_parse_mem(p, inst, true, false);
5183 case BC_LEX_STORE_IBASE:
5184 case BC_LEX_STORE_SCALE:
5185 case BC_LEX_STORE_OBASE:
5187 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5188 s = dc_parse_mem(p, inst, false, true);
5194 s = bc_error("bad token");
5200 if (!s && get_token) s = bc_lex_next(&p->l);
5205 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5207 BcStatus s = BC_STATUS_SUCCESS;
5211 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5213 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5215 inst = dc_parse_insts[t];
5217 if (inst != BC_INST_INVALID) {
5218 bc_parse_push(p, inst);
5219 s = bc_lex_next(&p->l);
5222 s = dc_parse_token(p, t, flags);
5225 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5226 bc_parse_push(p, BC_INST_POP_EXEC);
5231 static BcStatus dc_parse_parse(BcParse *p)
5235 if (p->l.t.t == BC_LEX_EOF)
5236 s = bc_error("end of file");
5238 s = dc_parse_expr(p, 0);
5240 if (s || G_interrupt) {
5242 s = BC_STATUS_FAILURE;
5248 static void dc_parse_init(BcParse *p, size_t func)
5250 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5254 static void common_parse_init(BcParse *p, size_t func)
5257 bc_parse_init(p, func);
5259 dc_parse_init(p, func);
5263 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5266 return bc_parse_expression(p, flags);
5268 return dc_parse_expr(p, flags);
5272 static BcVec* bc_program_search(char *id, bool var)
5280 v = var ? &G.prog.vars : &G.prog.arrs;
5281 map = var ? &G.prog.var_map : &G.prog.arr_map;
5285 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5288 bc_array_init(&data.v, var);
5289 bc_vec_push(v, &data.v);
5292 ptr = bc_vec_item(map, i);
5293 if (new) ptr->name = xstrdup(e.name);
5294 return bc_vec_item(v, ptr->idx);
5297 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5299 BcStatus s = BC_STATUS_SUCCESS;
5304 case BC_RESULT_TEMP:
5305 case BC_RESULT_IBASE:
5306 case BC_RESULT_SCALE:
5307 case BC_RESULT_OBASE:
5313 case BC_RESULT_CONSTANT:
5315 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5316 size_t base_t, len = strlen(*str);
5319 bc_num_init(&r->d.n, len);
5321 hex = hex && len == 1;
5322 base = hex ? &G.prog.hexb : &G.prog.ib;
5323 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5324 s = bc_num_parse(&r->d.n, *str, base, base_t);
5327 bc_num_free(&r->d.n);
5332 r->t = BC_RESULT_TEMP;
5338 case BC_RESULT_ARRAY:
5339 case BC_RESULT_ARRAY_ELEM:
5343 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5345 if (r->t == BC_RESULT_ARRAY_ELEM) {
5347 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5348 *num = bc_vec_item(v, r->d.id.idx);
5351 *num = bc_vec_top(v);
5356 case BC_RESULT_LAST:
5358 *num = &G.prog.last;
5372 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5373 BcResult **r, BcNum **rn, bool assign)
5377 BcResultType lt, rt;
5379 if (!BC_PROG_STACK(&G.prog.results, 2))
5380 return bc_error("stack has too few elements");
5382 *r = bc_vec_item_rev(&G.prog.results, 0);
5383 *l = bc_vec_item_rev(&G.prog.results, 1);
5387 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5389 s = bc_program_num(*l, ln, false);
5391 s = bc_program_num(*r, rn, hex);
5394 // We run this again under these conditions in case any vector has been
5395 // reallocated out from under the BcNums or arrays we had.
5396 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5397 s = bc_program_num(*l, ln, false);
5401 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5402 return bc_error("variable is wrong type");
5403 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5404 return bc_error("variable is wrong type");
5409 static void bc_program_binOpRetire(BcResult *r)
5411 r->t = BC_RESULT_TEMP;
5412 bc_vec_pop(&G.prog.results);
5413 bc_vec_pop(&G.prog.results);
5414 bc_vec_push(&G.prog.results, r);
5417 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5421 if (!BC_PROG_STACK(&G.prog.results, 1))
5422 return bc_error("stack has too few elements");
5423 *r = bc_vec_top(&G.prog.results);
5425 s = bc_program_num(*r, n, false);
5428 if (!BC_PROG_NUM((*r), (*n)))
5429 return bc_error("variable is wrong type");
5434 static void bc_program_retire(BcResult *r, BcResultType t)
5437 bc_vec_pop(&G.prog.results);
5438 bc_vec_push(&G.prog.results, r);
5441 static BcStatus bc_program_op(char inst)
5444 BcResult *opd1, *opd2, res;
5445 BcNum *n1, *n2 = NULL;
5447 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5449 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5451 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5453 bc_program_binOpRetire(&res);
5458 bc_num_free(&res.d.n);
5462 static BcStatus bc_program_read(void)
5469 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5471 for (i = 0; i < G.prog.stack.len; ++i) {
5472 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5473 if (ip_ptr->func == BC_PROG_READ)
5474 return bc_error("read() call inside of a read() call");
5477 bc_vec_npop(&f->code, f->code.len);
5478 bc_vec_init(&buf, sizeof(char), NULL);
5480 s = bc_read_line(&buf, "read> ");
5483 common_parse_init(&parse, BC_PROG_READ);
5484 bc_lex_file(&parse.l, bc_program_stdin_name);
5486 s = bc_parse_text(&parse, buf.v);
5487 if (s) goto exec_err;
5488 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5489 if (s) goto exec_err;
5491 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5492 s = bc_error("bad read() expression");
5496 ip.func = BC_PROG_READ;
5498 ip.len = G.prog.results.len;
5500 // Update this pointer, just in case.
5501 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5503 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5504 bc_vec_push(&G.prog.stack, &ip);
5507 bc_parse_free(&parse);
5513 static size_t bc_program_index(char *code, size_t *bgn)
5515 char amt = code[(*bgn)++], i = 0;
5518 for (; i < amt; ++i, ++(*bgn))
5519 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5524 static char *bc_program_name(char *code, size_t *bgn)
5527 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5529 s = xmalloc(ptr - str + 1);
5532 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5540 static void bc_program_printString(const char *str, size_t *nchars)
5542 size_t i, len = strlen(str);
5551 for (i = 0; i < len; ++i, ++(*nchars)) {
5555 if (c != '\\' || i == len - 1)
5615 // Just print the backslash and following character.
5626 static BcStatus bc_program_print(char inst, size_t idx)
5628 BcStatus s = BC_STATUS_SUCCESS;
5633 bool pop = inst != BC_INST_PRINT;
5635 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5636 return bc_error("stack has too few elements");
5638 r = bc_vec_item_rev(&G.prog.results, idx);
5639 s = bc_program_num(r, &num, false);
5642 if (BC_PROG_NUM(r, num)) {
5643 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5644 if (!s) bc_num_copy(&G.prog.last, num);
5648 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5649 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5651 if (inst == BC_INST_PRINT_STR) {
5652 for (i = 0, len = strlen(str); i < len; ++i) {
5655 if (c == '\n') G.prog.nchars = SIZE_MAX;
5660 bc_program_printString(str, &G.prog.nchars);
5661 if (inst == BC_INST_PRINT) bb_putchar('\n');
5665 if (!s && pop) bc_vec_pop(&G.prog.results);
5670 static BcStatus bc_program_negate(void)
5676 s = bc_program_prep(&ptr, &num);
5679 bc_num_init(&res.d.n, num->len);
5680 bc_num_copy(&res.d.n, num);
5681 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5683 bc_program_retire(&res, BC_RESULT_TEMP);
5688 static BcStatus bc_program_logical(char inst)
5691 BcResult *opd1, *opd2, res;
5696 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5698 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5700 if (inst == BC_INST_BOOL_AND)
5701 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5702 else if (inst == BC_INST_BOOL_OR)
5703 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5706 cmp = bc_num_cmp(n1, n2);
5710 case BC_INST_REL_EQ:
5716 case BC_INST_REL_LE:
5722 case BC_INST_REL_GE:
5728 case BC_INST_REL_NE:
5734 case BC_INST_REL_LT:
5740 case BC_INST_REL_GT:
5748 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5750 bc_program_binOpRetire(&res);
5756 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5762 memset(&n2, 0, sizeof(BcNum));
5763 n2.rdx = res.d.id.idx = r->d.id.idx;
5764 res.t = BC_RESULT_STR;
5767 if (!BC_PROG_STACK(&G.prog.results, 2))
5768 return bc_error("stack has too few elements");
5770 bc_vec_pop(&G.prog.results);
5773 bc_vec_pop(&G.prog.results);
5775 bc_vec_push(&G.prog.results, &res);
5776 bc_vec_push(v, &n2);
5778 return BC_STATUS_SUCCESS;
5782 static BcStatus bc_program_copyToVar(char *name, bool var)
5789 if (!BC_PROG_STACK(&G.prog.results, 1))
5790 return bc_error("stack has too few elements");
5792 ptr = bc_vec_top(&G.prog.results);
5793 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5794 return bc_error("variable is wrong type");
5795 v = bc_program_search(name, var);
5798 if (ptr->t == BC_RESULT_STR && !var)
5799 return bc_error("variable is wrong type");
5800 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5803 s = bc_program_num(ptr, &n, false);
5806 // Do this once more to make sure that pointers were not invalidated.
5807 v = bc_program_search(name, var);
5810 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5811 bc_num_copy(&r.d.n, n);
5814 bc_array_init(&r.d.v, true);
5815 bc_array_copy(&r.d.v, (BcVec *) n);
5818 bc_vec_push(v, &r.d);
5819 bc_vec_pop(&G.prog.results);
5824 static BcStatus bc_program_assign(char inst)
5827 BcResult *left, *right, res;
5828 BcNum *l = NULL, *r = NULL;
5829 unsigned long val, max;
5830 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5832 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5835 ib = left->t == BC_RESULT_IBASE;
5836 sc = left->t == BC_RESULT_SCALE;
5840 if (right->t == BC_RESULT_STR) {
5844 if (left->t != BC_RESULT_VAR)
5845 return bc_error("variable is wrong type");
5846 v = bc_program_search(left->d.id.name, true);
5848 return bc_program_assignStr(right, v, false);
5852 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5853 return bc_error("bad assignment:"
5854 " left side must be scale,"
5855 " ibase, obase, last, var,"
5860 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5861 return bc_error("divide by zero");
5866 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5873 if (ib || sc || left->t == BC_RESULT_OBASE) {
5874 static const char *const msg[] = {
5875 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5876 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5877 "?1", //BC_RESULT_LAST
5878 "?2", //BC_RESULT_CONSTANT
5879 "?3", //BC_RESULT_ONE
5880 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5884 s = bc_num_ulong(l, &val);
5887 s = left->t - BC_RESULT_IBASE;
5890 ptr = &G.prog.scale;
5893 if (val < BC_NUM_MIN_BASE)
5894 return bc_error(msg[s]);
5895 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5896 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5900 return bc_error(msg[s]);
5902 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5904 *ptr = (size_t) val;
5905 s = BC_STATUS_SUCCESS;
5908 bc_num_init(&res.d.n, l->len);
5909 bc_num_copy(&res.d.n, l);
5910 bc_program_binOpRetire(&res);
5916 #define bc_program_pushVar(code, bgn, pop, copy) \
5917 bc_program_pushVar(code, bgn)
5918 // for bc, 'pop' and 'copy' are always false
5920 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5921 bool pop, bool copy)
5923 BcStatus s = BC_STATUS_SUCCESS;
5925 char *name = bc_program_name(code, bgn);
5927 r.t = BC_RESULT_VAR;
5932 BcVec *v = bc_program_search(name, true);
5933 BcNum *num = bc_vec_top(v);
5937 if (!BC_PROG_STACK(v, 2 - copy)) {
5939 return bc_error("stack has too few elements");
5945 if (!BC_PROG_STR(num)) {
5947 r.t = BC_RESULT_TEMP;
5949 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5950 bc_num_copy(&r.d.n, num);
5953 r.t = BC_RESULT_STR;
5954 r.d.id.idx = num->rdx;
5957 if (!copy) bc_vec_pop(v);
5962 bc_vec_push(&G.prog.results, &r);
5967 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5970 BcStatus s = BC_STATUS_SUCCESS;
5974 r.d.id.name = bc_program_name(code, bgn);
5976 if (inst == BC_INST_ARRAY) {
5977 r.t = BC_RESULT_ARRAY;
5978 bc_vec_push(&G.prog.results, &r);
5985 s = bc_program_prep(&operand, &num);
5987 s = bc_num_ulong(num, &temp);
5990 if (temp > BC_MAX_DIM) {
5991 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
5995 r.d.id.idx = (size_t) temp;
5996 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
6000 if (s) free(r.d.id.name);
6005 static BcStatus bc_program_incdec(char inst)
6008 BcResult *ptr, res, copy;
6012 s = bc_program_prep(&ptr, &num);
6015 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6016 copy.t = BC_RESULT_TEMP;
6017 bc_num_init(©.d.n, num->len);
6018 bc_num_copy(©.d.n, num);
6021 res.t = BC_RESULT_ONE;
6022 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6023 BC_INST_ASSIGN_PLUS :
6024 BC_INST_ASSIGN_MINUS;
6026 bc_vec_push(&G.prog.results, &res);
6027 bc_program_assign(inst);
6029 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
6030 bc_vec_pop(&G.prog.results);
6031 bc_vec_push(&G.prog.results, ©);
6037 static BcStatus bc_program_call(char *code, size_t *idx)
6039 BcStatus s = BC_STATUS_SUCCESS;
6041 size_t i, nparams = bc_program_index(code, idx);
6048 ip.func = bc_program_index(code, idx);
6049 func = bc_vec_item(&G.prog.fns, ip.func);
6051 if (func->code.len == 0) {
6052 return bc_error("undefined function");
6054 if (nparams != func->nparams) {
6055 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
6057 ip.len = G.prog.results.len - nparams;
6059 for (i = 0; i < nparams; ++i) {
6061 a = bc_vec_item(&func->autos, nparams - 1 - i);
6062 arg = bc_vec_top(&G.prog.results);
6064 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6065 return bc_error("variable is wrong type");
6067 s = bc_program_copyToVar(a->name, a->idx);
6071 for (; i < func->autos.len; ++i) {
6074 a = bc_vec_item(&func->autos, i);
6075 v = bc_program_search(a->name, a->idx);
6078 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6079 bc_vec_push(v, ¶m.n);
6082 bc_array_init(¶m.v, true);
6083 bc_vec_push(v, ¶m.v);
6087 bc_vec_push(&G.prog.stack, &ip);
6089 return BC_STATUS_SUCCESS;
6092 static BcStatus bc_program_return(char inst)
6098 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6100 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6101 return bc_error("stack has too few elements");
6103 f = bc_vec_item(&G.prog.fns, ip->func);
6104 res.t = BC_RESULT_TEMP;
6106 if (inst == BC_INST_RET) {
6109 BcResult *operand = bc_vec_top(&G.prog.results);
6111 s = bc_program_num(operand, &num, false);
6113 bc_num_init(&res.d.n, num->len);
6114 bc_num_copy(&res.d.n, num);
6117 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6118 bc_num_zero(&res.d.n);
6121 // We need to pop arguments as well, so this takes that into account.
6122 for (i = 0; i < f->autos.len; ++i) {
6125 BcId *a = bc_vec_item(&f->autos, i);
6127 v = bc_program_search(a->name, a->idx);
6131 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6132 bc_vec_push(&G.prog.results, &res);
6133 bc_vec_pop(&G.prog.stack);
6135 return BC_STATUS_SUCCESS;
6139 static unsigned long bc_program_scale(BcNum *n)
6141 return (unsigned long) n->rdx;
6144 static unsigned long bc_program_len(BcNum *n)
6146 unsigned long len = n->len;
6149 if (n->rdx != n->len) return len;
6150 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6155 static BcStatus bc_program_builtin(char inst)
6161 bool len = inst == BC_INST_LENGTH;
6163 if (!BC_PROG_STACK(&G.prog.results, 1))
6164 return bc_error("stack has too few elements");
6165 opnd = bc_vec_top(&G.prog.results);
6167 s = bc_program_num(opnd, &num, false);
6171 if (!BC_PROG_NUM(opnd, num) && !len)
6172 return bc_error("variable is wrong type");
6175 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6177 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6179 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6180 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6184 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6187 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6189 str = bc_vec_item(&G.prog.strs, idx);
6190 bc_num_ulong2num(&res.d.n, strlen(*str));
6194 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6195 bc_num_ulong2num(&res.d.n, f(num));
6198 bc_program_retire(&res, BC_RESULT_TEMP);
6204 static BcStatus bc_program_divmod(void)
6207 BcResult *opd1, *opd2, res, res2;
6208 BcNum *n1, *n2 = NULL;
6210 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6213 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6214 bc_num_init(&res2.d.n, n2->len);
6216 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6219 bc_program_binOpRetire(&res2);
6220 res.t = BC_RESULT_TEMP;
6221 bc_vec_push(&G.prog.results, &res);
6226 bc_num_free(&res2.d.n);
6227 bc_num_free(&res.d.n);
6231 static BcStatus bc_program_modexp(void)
6234 BcResult *r1, *r2, *r3, res;
6235 BcNum *n1, *n2, *n3;
6237 if (!BC_PROG_STACK(&G.prog.results, 3))
6238 return bc_error("stack has too few elements");
6239 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6242 r1 = bc_vec_item_rev(&G.prog.results, 2);
6243 s = bc_program_num(r1, &n1, false);
6245 if (!BC_PROG_NUM(r1, n1))
6246 return bc_error("variable is wrong type");
6248 // Make sure that the values have their pointers updated, if necessary.
6249 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6251 if (r1->t == r2->t) {
6252 s = bc_program_num(r2, &n2, false);
6256 if (r1->t == r3->t) {
6257 s = bc_program_num(r3, &n3, false);
6262 bc_num_init(&res.d.n, n3->len);
6263 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6266 bc_vec_pop(&G.prog.results);
6267 bc_program_binOpRetire(&res);
6272 bc_num_free(&res.d.n);
6276 static void bc_program_stackLen(void)
6279 size_t len = G.prog.results.len;
6281 res.t = BC_RESULT_TEMP;
6283 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6284 bc_num_ulong2num(&res.d.n, len);
6285 bc_vec_push(&G.prog.results, &res);
6288 static BcStatus bc_program_asciify(void)
6292 BcNum *num = NULL, n;
6293 char *str, *str2, c;
6294 size_t len = G.prog.strs.len, idx;
6297 if (!BC_PROG_STACK(&G.prog.results, 1))
6298 return bc_error("stack has too few elements");
6299 r = bc_vec_top(&G.prog.results);
6301 s = bc_program_num(r, &num, false);
6304 if (BC_PROG_NUM(r, num)) {
6306 bc_num_init(&n, BC_NUM_DEF_SIZE);
6307 bc_num_copy(&n, num);
6308 bc_num_truncate(&n, n.rdx);
6310 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6311 if (s) goto num_err;
6312 s = bc_num_ulong(&n, &val);
6313 if (s) goto num_err;
6320 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6321 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6329 str2 = xstrdup(str);
6330 bc_program_addFunc(str2, &idx);
6332 if (idx != len + BC_PROG_REQ_FUNCS) {
6334 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6335 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6344 bc_vec_push(&G.prog.strs, &str);
6346 res.t = BC_RESULT_STR;
6348 bc_vec_pop(&G.prog.results);
6349 bc_vec_push(&G.prog.results, &res);
6351 return BC_STATUS_SUCCESS;
6358 static BcStatus bc_program_printStream(void)
6366 if (!BC_PROG_STACK(&G.prog.results, 1))
6367 return bc_error("stack has too few elements");
6368 r = bc_vec_top(&G.prog.results);
6370 s = bc_program_num(r, &n, false);
6373 if (BC_PROG_NUM(r, n))
6374 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6376 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6377 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6384 static BcStatus bc_program_nquit(void)
6391 s = bc_program_prep(&opnd, &num);
6393 s = bc_num_ulong(num, &val);
6396 bc_vec_pop(&G.prog.results);
6398 if (G.prog.stack.len < val)
6399 return bc_error("stack has too few elements");
6400 if (G.prog.stack.len == val)
6403 bc_vec_npop(&G.prog.stack, val);
6408 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6411 BcStatus s = BC_STATUS_SUCCESS;
6421 if (!BC_PROG_STACK(&G.prog.results, 1))
6422 return bc_error("stack has too few elements");
6424 r = bc_vec_top(&G.prog.results);
6428 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6430 if (code[*bgn] == BC_PARSE_STREND)
6433 else_name = bc_program_name(code, bgn);
6435 exec = r->d.n.len != 0;
6439 else if (else_name != NULL) {
6446 v = bc_program_search(name, true);
6453 if (!exec) goto exit;
6454 if (!BC_PROG_STR(n)) {
6455 s = bc_error("variable is wrong type");
6463 if (r->t == BC_RESULT_STR)
6465 else if (r->t == BC_RESULT_VAR) {
6466 s = bc_program_num(r, &n, false);
6467 if (s || !BC_PROG_STR(n)) goto exit;
6474 fidx = sidx + BC_PROG_REQ_FUNCS;
6476 str = bc_vec_item(&G.prog.strs, sidx);
6477 f = bc_vec_item(&G.prog.fns, fidx);
6479 if (f->code.len == 0) {
6480 common_parse_init(&prs, fidx);
6481 s = bc_parse_text(&prs, *str);
6483 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6486 if (prs.l.t.t != BC_LEX_EOF) {
6487 s = bc_error("bad expression");
6491 bc_parse_free(&prs);
6495 ip.len = G.prog.results.len;
6498 bc_vec_pop(&G.prog.results);
6499 bc_vec_push(&G.prog.stack, &ip);
6501 return BC_STATUS_SUCCESS;
6504 bc_parse_free(&prs);
6505 f = bc_vec_item(&G.prog.fns, fidx);
6506 bc_vec_npop(&f->code, f->code.len);
6508 bc_vec_pop(&G.prog.results);
6513 static void bc_program_pushGlobal(char inst)
6518 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6519 if (inst == BC_INST_IBASE)
6520 val = (unsigned long) G.prog.ib_t;
6521 else if (inst == BC_INST_SCALE)
6522 val = (unsigned long) G.prog.scale;
6524 val = (unsigned long) G.prog.ob_t;
6526 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6527 bc_num_ulong2num(&res.d.n, val);
6528 bc_vec_push(&G.prog.results, &res);
6531 static void bc_program_addFunc(char *name, size_t *idx)
6533 BcId entry, *entry_ptr;
6538 entry.idx = G.prog.fns.len;
6540 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6541 if (!inserted) free(name);
6543 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6544 *idx = entry_ptr->idx;
6548 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6550 // We need to reset these, so the function can be repopulated.
6552 bc_vec_npop(&func->autos, func->autos.len);
6553 bc_vec_npop(&func->code, func->code.len);
6554 bc_vec_npop(&func->labels, func->labels.len);
6558 bc_vec_push(&G.prog.fns, &f);
6562 // Called when parsing or execution detects a failure,
6563 // resets execution structures.
6564 static void bc_program_reset(void)
6569 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6570 bc_vec_npop(&G.prog.results, G.prog.results.len);
6572 f = bc_vec_item(&G.prog.fns, 0);
6573 ip = bc_vec_top(&G.prog.stack);
6574 ip->idx = f->code.len;
6576 // If !tty, no need to check for ^C: we don't have ^C handler,
6577 // we would be killed by a signal and won't reach this place
6579 fflush_and_check(); // make sure buffered stdout is printed
6580 fputs("ready for more input\n", stderr);
6584 static BcStatus bc_program_exec(void)
6586 BcStatus s = BC_STATUS_SUCCESS;
6590 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6591 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6592 char *code = func->code.v;
6595 while (!s && ip->idx < func->code.len) {
6597 char inst = code[(ip->idx)++];
6602 case BC_INST_JUMP_ZERO:
6604 s = bc_program_prep(&ptr, &num);
6606 cond = !bc_num_cmp(num, &G.prog.zero);
6607 bc_vec_pop(&G.prog.results);
6613 idx = bc_program_index(code, &ip->idx);
6614 addr = bc_vec_item(&func->labels, idx);
6615 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6621 s = bc_program_call(code, &ip->idx);
6625 case BC_INST_INC_PRE:
6626 case BC_INST_DEC_PRE:
6627 case BC_INST_INC_POST:
6628 case BC_INST_DEC_POST:
6630 s = bc_program_incdec(inst);
6643 s = bc_program_return(inst);
6647 case BC_INST_BOOL_OR:
6648 case BC_INST_BOOL_AND:
6650 case BC_INST_REL_EQ:
6651 case BC_INST_REL_LE:
6652 case BC_INST_REL_GE:
6653 case BC_INST_REL_NE:
6654 case BC_INST_REL_LT:
6655 case BC_INST_REL_GT:
6657 s = bc_program_logical(inst);
6663 s = bc_program_read();
6669 s = bc_program_pushVar(code, &ip->idx, false, false);
6673 case BC_INST_ARRAY_ELEM:
6676 s = bc_program_pushArray(code, &ip->idx, inst);
6682 r.t = BC_RESULT_LAST;
6683 bc_vec_push(&G.prog.results, &r);
6691 bc_program_pushGlobal(inst);
6695 case BC_INST_SCALE_FUNC:
6696 case BC_INST_LENGTH:
6699 s = bc_program_builtin(inst);
6705 r.t = BC_RESULT_CONSTANT;
6706 r.d.id.idx = bc_program_index(code, &ip->idx);
6707 bc_vec_push(&G.prog.results, &r);
6713 if (!BC_PROG_STACK(&G.prog.results, 1))
6714 s = bc_error("stack has too few elements");
6716 bc_vec_pop(&G.prog.results);
6720 case BC_INST_POP_EXEC:
6722 bc_vec_pop(&G.prog.stack);
6727 case BC_INST_PRINT_POP:
6728 case BC_INST_PRINT_STR:
6730 s = bc_program_print(inst, 0);
6736 r.t = BC_RESULT_STR;
6737 r.d.id.idx = bc_program_index(code, &ip->idx);
6738 bc_vec_push(&G.prog.results, &r);
6743 case BC_INST_MULTIPLY:
6744 case BC_INST_DIVIDE:
6745 case BC_INST_MODULUS:
6749 s = bc_program_op(inst);
6753 case BC_INST_BOOL_NOT:
6755 s = bc_program_prep(&ptr, &num);
6758 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6759 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6760 bc_program_retire(&r, BC_RESULT_TEMP);
6767 s = bc_program_negate();
6772 case BC_INST_ASSIGN_POWER:
6773 case BC_INST_ASSIGN_MULTIPLY:
6774 case BC_INST_ASSIGN_DIVIDE:
6775 case BC_INST_ASSIGN_MODULUS:
6776 case BC_INST_ASSIGN_PLUS:
6777 case BC_INST_ASSIGN_MINUS:
6779 case BC_INST_ASSIGN:
6781 s = bc_program_assign(inst);
6785 case BC_INST_MODEXP:
6787 s = bc_program_modexp();
6791 case BC_INST_DIVMOD:
6793 s = bc_program_divmod();
6797 case BC_INST_EXECUTE:
6798 case BC_INST_EXEC_COND:
6800 cond = inst == BC_INST_EXEC_COND;
6801 s = bc_program_execStr(code, &ip->idx, cond);
6805 case BC_INST_PRINT_STACK:
6807 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6808 s = bc_program_print(BC_INST_PRINT, idx);
6812 case BC_INST_CLEAR_STACK:
6814 bc_vec_npop(&G.prog.results, G.prog.results.len);
6818 case BC_INST_STACK_LEN:
6820 bc_program_stackLen();
6824 case BC_INST_DUPLICATE:
6826 if (!BC_PROG_STACK(&G.prog.results, 1))
6827 return bc_error("stack has too few elements");
6828 ptr = bc_vec_top(&G.prog.results);
6829 bc_result_copy(&r, ptr);
6830 bc_vec_push(&G.prog.results, &r);
6838 if (!BC_PROG_STACK(&G.prog.results, 2))
6839 return bc_error("stack has too few elements");
6841 ptr = bc_vec_item_rev(&G.prog.results, 0);
6842 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6843 memcpy(&r, ptr, sizeof(BcResult));
6844 memcpy(ptr, ptr2, sizeof(BcResult));
6845 memcpy(ptr2, &r, sizeof(BcResult));
6850 case BC_INST_ASCIIFY:
6852 s = bc_program_asciify();
6856 case BC_INST_PRINT_STREAM:
6858 s = bc_program_printStream();
6863 case BC_INST_PUSH_VAR:
6865 bool copy = inst == BC_INST_LOAD;
6866 s = bc_program_pushVar(code, &ip->idx, true, copy);
6870 case BC_INST_PUSH_TO_VAR:
6872 char *name = bc_program_name(code, &ip->idx);
6873 s = bc_program_copyToVar(name, true);
6880 if (G.prog.stack.len <= 2)
6882 bc_vec_npop(&G.prog.stack, 2);
6888 s = bc_program_nquit();
6894 if (s || G_interrupt) {
6899 // If the stack has changed, pointers may be invalid.
6900 ip = bc_vec_top(&G.prog.stack);
6901 func = bc_vec_item(&G.prog.fns, ip->func);
6902 code = func->code.v;
6908 static void bc_vm_info(void)
6910 printf("%s "BB_VER"\n"
6911 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6912 "Report bugs at: https://github.com/gavinhoward/bc\n"
6913 "This is free software with ABSOLUTELY NO WARRANTY\n"
6917 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6919 if (!s || s > BC_STATUS_BEFORE_POSIX) return s;
6921 if (bc_err_msgs[s]) {
6922 fprintf(stderr, bc_err_fmt, bc_err_msgs[s]);
6923 fprintf(stderr, " %s", file);
6924 fprintf(stderr, bc_err_line + 4 * !line, line);
6928 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6932 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6937 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W))) return BC_STATUS_SUCCESS;
6938 if (s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6940 fmt = G_posix ? bc_err_fmt : bc_warn_fmt;
6941 fprintf(stderr, fmt, bc_err_msgs[s]);
6942 if (msg) fprintf(stderr, " %s\n", msg);
6943 fprintf(stderr, " %s", file);
6944 fprintf(stderr, bc_err_line + 4 * !line, line);
6946 if (G.ttyin || !G_posix)
6947 s = BC_STATUS_SUCCESS;
6951 static void bc_vm_envArgs(void)
6953 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6956 char *env_args = getenv(bc_args_env_name), *buf;
6958 if (!env_args) return;
6960 G.env_args = xstrdup(env_args);
6963 bc_vec_init(&v, sizeof(char *), NULL);
6964 bc_vec_push(&v, &bc_args_env_name);
6967 if (!isspace(*buf)) {
6968 bc_vec_push(&v, &buf);
6969 while (*buf != 0 && !isspace(*buf)) ++buf;
6970 if (*buf != 0) (*(buf++)) = '\0';
6976 bc_args((int) v.len, (char **) v.v);
6982 static size_t bc_vm_envLen(const char *var)
6984 char *lenv = getenv(var);
6985 size_t i, len = BC_NUM_PRINT_WIDTH;
6988 if (!lenv) return len;
6992 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6994 len = (size_t) atoi(lenv) - 1;
6995 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6998 len = BC_NUM_PRINT_WIDTH;
7003 static BcStatus bc_vm_process(const char *text)
7005 BcStatus s = bc_parse_text(&G.prs, text);
7007 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
7010 while (G.prs.l.t.t != BC_LEX_EOF) {
7012 s = G.prs.parse(&G.prs);
7014 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
7018 if (BC_PARSE_CAN_EXEC(&G.prs)) {
7019 s = bc_program_exec();
7023 s = bc_vm_error(s, G.prs.l.f, 0);
7030 static BcStatus bc_vm_file(const char *file)
7038 data = bc_read_file(file);
7039 if (!data) return bc_error("file '%s' is not text", file);
7041 bc_lex_file(&G.prs.l, file);
7042 s = bc_vm_process(data);
7045 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7046 ip = bc_vec_item(&G.prog.stack, 0);
7048 if (main_func->code.len < ip->idx)
7049 s = bc_error("file '%s' is not executable", file);
7056 static BcStatus bc_vm_stdin(void)
7060 size_t len, i, str = 0;
7061 bool comment = false;
7063 G.prog.file = bc_program_stdin_name;
7064 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7066 bc_vec_init(&buffer, sizeof(char), NULL);
7067 bc_vec_init(&buf, sizeof(char), NULL);
7068 bc_vec_pushByte(&buffer, '\0');
7070 // This loop is complex because the vm tries not to send any lines that end
7071 // with a backslash to the parser. The reason for that is because the parser
7072 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7073 // case, and for strings and comments, the parser will expect more stuff.
7074 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7076 char *string = buf.v;
7081 if (str && buf.v[0] == G.send)
7083 else if (buf.v[0] == G.sbgn)
7086 else if (len > 1 || comment) {
7088 for (i = 0; i < len; ++i) {
7090 bool notend = len > i + 1;
7093 if (i - 1 > len || string[i - 1] != '\\') {
7094 if (G.sbgn == G.send)
7096 else if (c == G.send)
7098 else if (c == G.sbgn)
7102 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7106 else if (c == '*' && notend && comment && string[i + 1] == '/')
7110 if (str || comment || string[len - 2] == '\\') {
7111 bc_vec_concat(&buffer, buf.v);
7116 bc_vec_concat(&buffer, buf.v);
7117 s = bc_vm_process(buffer.v);
7120 bc_vec_npop(&buffer, buffer.len);
7124 bc_error("string end could not be found");
7125 s = bc_vm_error(BC_STATUS_FAILURE, G.prs.l.f,
7129 bc_error("comment end could not be found");
7130 s = bc_vm_error(BC_STATUS_FAILURE, G.prs.l.f,
7136 bc_vec_free(&buffer);
7140 static BcStatus bc_vm_exec(void)
7142 BcStatus s = BC_STATUS_SUCCESS;
7146 if (G.flags & BC_FLAG_L) {
7148 bc_lex_file(&G.prs.l, bc_lib_name);
7149 s = bc_parse_text(&G.prs, bc_lib);
7151 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7154 s = bc_program_exec();
7159 for (i = 0; !s && i < G.files.len; ++i)
7160 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7163 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7164 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7169 #if ENABLE_FEATURE_CLEAN_UP
7170 static void bc_program_free()
7172 bc_num_free(&G.prog.ib);
7173 bc_num_free(&G.prog.ob);
7174 bc_num_free(&G.prog.hexb);
7176 bc_num_free(&G.prog.strmb);
7178 bc_vec_free(&G.prog.fns);
7179 bc_vec_free(&G.prog.fn_map);
7180 bc_vec_free(&G.prog.vars);
7181 bc_vec_free(&G.prog.var_map);
7182 bc_vec_free(&G.prog.arrs);
7183 bc_vec_free(&G.prog.arr_map);
7184 bc_vec_free(&G.prog.strs);
7185 bc_vec_free(&G.prog.consts);
7186 bc_vec_free(&G.prog.results);
7187 bc_vec_free(&G.prog.stack);
7188 bc_num_free(&G.prog.last);
7189 bc_num_free(&G.prog.zero);
7190 bc_num_free(&G.prog.one);
7193 static void bc_vm_free(void)
7195 bc_vec_free(&G.files);
7197 bc_parse_free(&G.prs);
7202 static void bc_program_init(size_t line_len)
7207 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7208 memset(&ip, 0, sizeof(BcInstPtr));
7210 /* G.prog.nchars = G.prog.scale = 0; - already is */
7211 G.prog.len = line_len;
7213 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7214 bc_num_ten(&G.prog.ib);
7217 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7218 bc_num_ten(&G.prog.ob);
7221 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7222 bc_num_ten(&G.prog.hexb);
7223 G.prog.hexb.num[0] = 6;
7226 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7227 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7230 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7231 bc_num_zero(&G.prog.last);
7233 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7234 bc_num_zero(&G.prog.zero);
7236 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7237 bc_num_one(&G.prog.one);
7239 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7240 bc_map_init(&G.prog.fn_map);
7242 bc_program_addFunc(xstrdup("(main)"), &idx);
7243 bc_program_addFunc(xstrdup("(read)"), &idx);
7245 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7246 bc_map_init(&G.prog.var_map);
7248 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7249 bc_map_init(&G.prog.arr_map);
7251 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7252 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7253 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7254 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7255 bc_vec_push(&G.prog.stack, &ip);
7258 static void bc_vm_init(const char *env_len)
7260 size_t len = bc_vm_envLen(env_len);
7262 bc_vec_init(&G.files, sizeof(char *), NULL);
7265 if (getenv("POSIXLY_CORRECT"))
7266 G.flags |= BC_FLAG_S;
7270 bc_program_init(len);
7272 bc_parse_init(&G.prs, BC_PROG_MAIN);
7274 dc_parse_init(&G.prs, BC_PROG_MAIN);
7278 static BcStatus bc_vm_run(int argc, char *argv[],
7279 const char *env_len)
7283 bc_vm_init(env_len);
7284 bc_args(argc, argv);
7286 G.ttyin = isatty(0);
7287 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7290 #if ENABLE_FEATURE_BC_SIGNALS
7291 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7293 if (!(G.flags & BC_FLAG_Q))
7298 #if ENABLE_FEATURE_CLEAN_UP
7305 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7306 int bc_main(int argc, char **argv)
7309 G.sbgn = G.send = '"';
7311 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7316 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7317 int dc_main(int argc, char **argv)
7323 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");