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 {
174 // BC_STATUS_ALLOC_ERR,
175 // BC_STATUS_INPUT_EOF,
176 // BC_STATUS_BIN_FILE,
177 // BC_STATUS_PATH_IS_DIR,
179 // BC_STATUS_LEX_BAD_CHAR,
180 BC_STATUS_LEX_NO_STRING_END,
181 BC_STATUS_LEX_NO_COMMENT_END,
184 BC_STATUS_LEX_EXTENDED_REG,
186 BC_STATUS_PARSE_BAD_TOKEN,
187 BC_STATUS_PARSE_BAD_EXP,
188 BC_STATUS_PARSE_EMPTY_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_EXEC_STACK,
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[] = {
245 // "memory allocation error",
247 // "file is not text:",
248 // "path is a directory:",
251 "string end could not be found",
252 "comment end could not be found",
260 "bad print statement",
261 "bad function definition",
262 "bad assignment: left side must be scale, ibase, "
263 "obase, last, var, or array element",
264 // "no auto variable found",
265 "function parameter or auto var has the same name as another",
266 "block end could not be found",
269 "non integer number",
274 // "could not open file:",
275 // "mismatched parameters", // wrong number of them, to be exact
276 // "undefined function",
277 "file is not executable:",
278 "number too long: must be [1, BC_NUM_MAX]",
279 "name too long: must be [1, BC_NAME_MAX]",
280 "string too long: must be [1, BC_STRING_MAX]",
281 "array too long; must be [1, BC_DIM_MAX]",
282 "bad ibase; must be [2, 16]",
283 // "bad scale; must be [0, BC_SCALE_MAX]",
284 "bad read() expression",
285 "read() call inside of a read() call",
286 "variable is wrong type",
287 // "bad obase; must be [2, BC_BASE_MAX]",
288 "signal caught and not handled",
289 "stack has too few elements",
291 // "index is out of bounds",
292 // "item already exists",
294 "POSIX only allows one character names; the following is bad:",
295 "POSIX does not allow '#' script comments",
296 "POSIX does not allow the following keyword:",
297 "POSIX does not allow a period ('.') as a shortcut for the last result",
298 "POSIX requires parentheses around return expressions",
299 "POSIX does not allow boolean operators; the following is bad:",
300 "POSIX does not allow comparison operators outside if or loops",
301 "POSIX requires exactly one comparison operator per condition",
302 "POSIX does not allow an empty init expression in a for loop",
303 "POSIX does not allow an empty condition expression in a for loop",
304 "POSIX does not allow an empty update expression in a for loop",
305 "POSIX requires the left brace be on the same line as the function header",
309 #define BC_VEC_INVALID_IDX ((size_t) -1)
310 #define BC_VEC_START_CAP (1 << 5)
312 typedef void (*BcVecFree)(void *);
314 typedef struct BcVec {
322 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
323 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
325 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
327 typedef signed char BcDig;
329 typedef struct BcNum {
337 #define BC_NUM_MIN_BASE ((unsigned long) 2)
338 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
339 #define BC_NUM_DEF_SIZE (16)
340 #define BC_NUM_PRINT_WIDTH (69)
342 #define BC_NUM_KARATSUBA_LEN (32)
344 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
345 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
346 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
347 #define BC_NUM_AREQ(a, b) \
348 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
349 #define BC_NUM_MREQ(a, b, scale) \
350 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
352 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
353 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
355 static void bc_num_init(BcNum *n, size_t req);
356 static void bc_num_expand(BcNum *n, size_t req);
357 static void bc_num_copy(BcNum *d, BcNum *s);
358 static void bc_num_free(void *num);
360 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
361 static void bc_num_ulong2num(BcNum *n, unsigned long val);
363 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
364 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
365 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
366 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
367 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
368 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
369 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
370 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
373 typedef enum BcInst {
403 BC_INST_ASSIGN_POWER,
404 BC_INST_ASSIGN_MULTIPLY,
405 BC_INST_ASSIGN_DIVIDE,
406 BC_INST_ASSIGN_MODULUS,
408 BC_INST_ASSIGN_MINUS,
454 BC_INST_PRINT_STREAM,
469 BC_INST_INVALID = -1,
474 typedef struct BcId {
479 typedef struct BcFunc {
486 typedef enum BcResultType {
491 BC_RESULT_ARRAY_ELEM,
500 // These are between to calculate ibase, obase, and last from instructions.
508 typedef union BcResultData {
514 typedef struct BcResult {
519 typedef struct BcInstPtr {
525 static void bc_array_expand(BcVec *a, size_t len);
526 static int bc_id_cmp(const void *e1, const void *e2);
528 // BC_LEX_NEG is not used in lexing; it is only for parsing.
529 typedef enum BcLexType {
557 BC_LEX_OP_ASSIGN_POWER,
558 BC_LEX_OP_ASSIGN_MULTIPLY,
559 BC_LEX_OP_ASSIGN_DIVIDE,
560 BC_LEX_OP_ASSIGN_MODULUS,
561 BC_LEX_OP_ASSIGN_PLUS,
562 BC_LEX_OP_ASSIGN_MINUS,
636 typedef BcStatus (*BcLexNext)(struct BcLex *);
638 typedef struct BcLex {
657 #define BC_PARSE_STREND ((char) UCHAR_MAX)
659 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
660 #define bc_parse_updateFunc(p, f) \
661 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
663 #define BC_PARSE_REL (1 << 0)
664 #define BC_PARSE_PRINT (1 << 1)
665 #define BC_PARSE_NOCALL (1 << 2)
666 #define BC_PARSE_NOREAD (1 << 3)
667 #define BC_PARSE_ARRAY (1 << 4)
669 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
670 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
672 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
673 #define BC_PARSE_FUNC_INNER(parse) \
674 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
676 #define BC_PARSE_FLAG_FUNC (1 << 1)
677 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
679 #define BC_PARSE_FLAG_BODY (1 << 2)
680 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
682 #define BC_PARSE_FLAG_LOOP (1 << 3)
683 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
685 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
686 #define BC_PARSE_LOOP_INNER(parse) \
687 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
689 #define BC_PARSE_FLAG_IF (1 << 5)
690 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
692 #define BC_PARSE_FLAG_ELSE (1 << 6)
693 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
695 #define BC_PARSE_FLAG_IF_END (1 << 7)
696 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
698 #define BC_PARSE_CAN_EXEC(parse) \
699 (!(BC_PARSE_TOP_FLAG(parse) & \
700 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
701 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
702 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
704 typedef struct BcOp {
709 typedef struct BcParseNext {
714 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
715 #define BC_PARSE_NEXT(a, ...) \
717 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
724 typedef BcStatus (*BcParseParse)(struct BcParse *);
726 typedef struct BcParse {
749 typedef struct BcLexKeyword {
755 #define BC_LEX_KW_ENTRY(a, b, c) \
757 .name = a, .len = (b), .posix = (c) \
760 static BcStatus bc_lex_token(BcLex *l);
762 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
763 #define BC_PARSE_LEAF(p, rparen) \
764 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
765 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
767 // We can calculate the conversion between tokens and exprs by subtracting the
768 // position of the first operator in the lex enum and adding the position of the
769 // first in the expr enum. Note: This only works for binary operators.
770 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
772 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
778 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
780 static BcStatus dc_lex_token(BcLex *l);
782 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
786 typedef struct BcProgram {
827 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
829 #define BC_PROG_MAIN (0)
830 #define BC_PROG_READ (1)
833 #define BC_PROG_REQ_FUNCS (2)
836 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
837 #define BC_PROG_NUM(r, n) \
838 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
840 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
842 static void bc_program_addFunc(char *name, size_t *idx);
843 static BcStatus bc_program_reset(BcStatus s);
845 #define BC_FLAG_X (1 << 0)
846 #define BC_FLAG_W (1 << 1)
847 #define BC_FLAG_V (1 << 2)
848 #define BC_FLAG_S (1 << 3)
849 #define BC_FLAG_Q (1 << 4)
850 #define BC_FLAG_L (1 << 5)
851 #define BC_FLAG_I (1 << 6)
853 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
854 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
856 #define BC_MAX_OBASE ((unsigned) 999)
857 #define BC_MAX_DIM ((unsigned) INT_MAX)
858 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
859 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
860 #define BC_MAX_NAME BC_MAX_STRING
861 #define BC_MAX_NUM BC_MAX_STRING
862 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
863 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
881 #define G (*ptr_to_globals)
882 #define INIT_G() do { \
883 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
885 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
886 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
887 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
888 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
891 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
894 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
898 static void bc_vm_info(void);
900 static const char bc_err_fmt[] = "\nerror: %s\n";
901 static const char bc_warn_fmt[] = "\nwarning: %s\n";
902 static const char bc_err_line[] = ":%zu\n\n";
905 static const BcLexKeyword bc_lex_kws[20] = {
906 BC_LEX_KW_ENTRY("auto", 4, true),
907 BC_LEX_KW_ENTRY("break", 5, true),
908 BC_LEX_KW_ENTRY("continue", 8, false),
909 BC_LEX_KW_ENTRY("define", 6, true),
910 BC_LEX_KW_ENTRY("else", 4, false),
911 BC_LEX_KW_ENTRY("for", 3, true),
912 BC_LEX_KW_ENTRY("halt", 4, false),
913 BC_LEX_KW_ENTRY("ibase", 5, true),
914 BC_LEX_KW_ENTRY("if", 2, true),
915 BC_LEX_KW_ENTRY("last", 4, false),
916 BC_LEX_KW_ENTRY("length", 6, true),
917 BC_LEX_KW_ENTRY("limits", 6, false),
918 BC_LEX_KW_ENTRY("obase", 5, true),
919 BC_LEX_KW_ENTRY("print", 5, false),
920 BC_LEX_KW_ENTRY("quit", 4, true),
921 BC_LEX_KW_ENTRY("read", 4, false),
922 BC_LEX_KW_ENTRY("return", 6, true),
923 BC_LEX_KW_ENTRY("scale", 5, true),
924 BC_LEX_KW_ENTRY("sqrt", 4, true),
925 BC_LEX_KW_ENTRY("while", 5, true),
928 // This is an array that corresponds to token types. An entry is
929 // true if the token is valid in an expression, false otherwise.
930 static const bool bc_parse_exprs[] = {
931 false, false, true, true, true, true, true, true, true, true, true, true,
932 true, true, true, true, true, true, true, true, true, true, true, true,
933 true, true, true, false, false, true, true, false, false, false, false,
934 false, false, false, true, true, false, false, false, false, false, false,
935 false, true, false, true, true, true, true, false, false, true, false, true,
939 // This is an array of data for operators that correspond to token types.
940 static const BcOp bc_parse_ops[] = {
941 { 0, false }, { 0, false },
944 { 3, true }, { 3, true }, { 3, true },
945 { 4, true }, { 4, true },
946 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
948 { 7, true }, { 7, true },
949 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
950 { 5, false }, { 5, false },
953 // These identify what tokens can come after expressions in certain cases.
954 static const BcParseNext bc_parse_next_expr =
955 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
956 static const BcParseNext bc_parse_next_param =
957 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
958 static const BcParseNext bc_parse_next_print =
959 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
960 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
961 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
962 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
963 static const BcParseNext bc_parse_next_read =
964 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
968 static const BcLexType dc_lex_regs[] = {
969 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
970 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
971 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
975 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
977 static const BcLexType dc_lex_tokens[] = {
978 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
979 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
980 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
981 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
982 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
983 BC_LEX_INVALID, BC_LEX_INVALID,
984 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
985 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
986 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
987 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
988 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
989 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
990 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
991 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
992 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
993 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
994 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
995 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
996 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
997 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
998 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
999 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1000 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1001 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1005 static const BcInst dc_parse_insts[] = {
1006 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1007 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1008 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1009 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1010 BC_INST_INVALID, BC_INST_INVALID,
1011 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1012 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1013 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1014 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1015 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1016 BC_INST_INVALID, BC_INST_INVALID,
1017 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1018 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1019 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1020 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1021 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1022 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1023 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1024 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1025 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1026 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1027 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1028 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1032 static const BcNumBinaryOp bc_program_ops[] = {
1033 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1036 static const char bc_program_stdin_name[] = "<stdin>";
1037 static const char bc_program_ready_msg[] = "ready for more input\n";
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) return BC_STATUS_EXEC_NUM_LEN;
1583 if (n->rdx >= places)
1586 bc_num_extend(n, places - n->rdx);
1592 return BC_STATUS_SUCCESS;
1595 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1604 return bc_num_div(&one, a, b, scale);
1607 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1609 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1610 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1613 // Because this function doesn't need to use scale (per the bc spec),
1614 // I am hijacking it to say whether it's doing an add or a subtract.
1618 if (sub && c->len) c->neg = !c->neg;
1619 return BC_STATUS_SUCCESS;
1621 else if (b->len == 0) {
1623 return BC_STATUS_SUCCESS;
1627 c->rdx = BC_MAX(a->rdx, b->rdx);
1628 min_rdx = BC_MIN(a->rdx, b->rdx);
1631 if (a->rdx > b->rdx) {
1632 diff = a->rdx - b->rdx;
1634 ptr_a = a->num + diff;
1638 diff = b->rdx - a->rdx;
1641 ptr_b = b->num + diff;
1644 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1647 a_int = BC_NUM_INT(a);
1648 b_int = BC_NUM_INT(b);
1650 if (a_int > b_int) {
1661 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1662 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1664 ptr_c[i] = (BcDig)(in % 10);
1667 for (; i < max + min_rdx; ++i, ++c->len) {
1668 in = ((int) ptr[i]) + carry;
1670 ptr_c[i] = (BcDig)(in % 10);
1673 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1675 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1678 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1681 BcNum *minuend, *subtrahend;
1683 bool aneg, bneg, neg;
1685 // Because this function doesn't need to use scale (per the bc spec),
1686 // I am hijacking it to say whether it's doing an add or a subtract.
1690 if (sub && c->len) c->neg = !c->neg;
1691 return BC_STATUS_SUCCESS;
1693 else if (b->len == 0) {
1695 return BC_STATUS_SUCCESS;
1700 a->neg = b->neg = false;
1702 cmp = bc_num_cmp(a, b);
1708 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1709 return BC_STATUS_SUCCESS;
1718 if (sub) neg = !neg;
1723 bc_num_copy(c, minuend);
1726 if (c->rdx < subtrahend->rdx) {
1727 bc_num_extend(c, subtrahend->rdx - c->rdx);
1731 start = c->rdx - subtrahend->rdx;
1733 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1737 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1740 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1745 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1746 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1747 bool aone = BC_NUM_ONE(a);
1749 if (a->len == 0 || b->len == 0) {
1751 return BC_STATUS_SUCCESS;
1753 else if (aone || BC_NUM_ONE(b)) {
1754 bc_num_copy(c, aone ? b : a);
1755 return BC_STATUS_SUCCESS;
1758 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1759 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1761 bc_num_expand(c, a->len + b->len + 1);
1763 memset(c->num, 0, sizeof(BcDig) * c->cap);
1764 c->len = carry = len = 0;
1766 for (i = 0; i < b->len; ++i) {
1768 for (j = 0; j < a->len; ++j) {
1769 int in = (int) c->num[i + j];
1770 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1772 c->num[i + j] = (BcDig)(in % 10);
1775 c->num[i + j] += (BcDig) carry;
1776 len = BC_MAX(len, i + j + !!carry);
1782 return BC_STATUS_SUCCESS;
1785 bc_num_init(&l1, max);
1786 bc_num_init(&h1, max);
1787 bc_num_init(&l2, max);
1788 bc_num_init(&h2, max);
1789 bc_num_init(&m1, max);
1790 bc_num_init(&m2, max);
1791 bc_num_init(&z0, max);
1792 bc_num_init(&z1, max);
1793 bc_num_init(&z2, max);
1794 bc_num_init(&temp, max + max);
1796 bc_num_split(a, max2, &l1, &h1);
1797 bc_num_split(b, max2, &l2, &h2);
1799 s = bc_num_add(&h1, &l1, &m1, 0);
1801 s = bc_num_add(&h2, &l2, &m2, 0);
1804 s = bc_num_k(&h1, &h2, &z0);
1806 s = bc_num_k(&m1, &m2, &z1);
1808 s = bc_num_k(&l1, &l2, &z2);
1811 s = bc_num_sub(&z1, &z0, &temp, 0);
1813 s = bc_num_sub(&temp, &z2, &z1, 0);
1816 s = bc_num_shift(&z0, max2 * 2);
1818 s = bc_num_shift(&z1, max2);
1820 s = bc_num_add(&z0, &z1, &temp, 0);
1822 s = bc_num_add(&temp, &z2, c, 0);
1838 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1842 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1844 scale = BC_MAX(scale, a->rdx);
1845 scale = BC_MAX(scale, b->rdx);
1846 scale = BC_MIN(a->rdx + b->rdx, scale);
1847 maxrdx = BC_MAX(maxrdx, scale);
1849 bc_num_init(&cpa, a->len);
1850 bc_num_init(&cpb, b->len);
1852 bc_num_copy(&cpa, a);
1853 bc_num_copy(&cpb, b);
1854 cpa.neg = cpb.neg = false;
1856 s = bc_num_shift(&cpa, maxrdx);
1858 s = bc_num_shift(&cpb, maxrdx);
1860 s = bc_num_k(&cpa, &cpb, c);
1864 bc_num_expand(c, c->len + maxrdx);
1866 if (c->len < maxrdx) {
1867 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1872 bc_num_retireMul(c, scale, a->neg, b->neg);
1880 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1882 BcStatus s = BC_STATUS_SUCCESS;
1889 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1890 else if (a->len == 0) {
1891 bc_num_setToZero(c, scale);
1892 return BC_STATUS_SUCCESS;
1894 else if (BC_NUM_ONE(b)) {
1896 bc_num_retireMul(c, scale, a->neg, b->neg);
1897 return BC_STATUS_SUCCESS;
1900 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1901 bc_num_copy(&cp, a);
1905 bc_num_expand(&cp, len + 2);
1906 bc_num_extend(&cp, len - cp.len);
1909 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1911 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1913 if (b->rdx == b->len) {
1914 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1918 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1920 // We want an extra zero in front to make things simpler.
1921 cp.num[cp.len++] = 0;
1924 bc_num_expand(c, cp.len);
1927 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1932 for (i = end - 1; !s && i < end; --i) {
1934 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1935 bc_num_subArrays(n, p, len);
1939 bc_num_retireMul(c, scale, a->neg, b->neg);
1942 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1945 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1946 BcNum *restrict d, size_t scale, size_t ts)
1952 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1955 bc_num_setToZero(d, ts);
1956 return BC_STATUS_SUCCESS;
1959 bc_num_init(&temp, d->cap);
1960 bc_num_d(a, b, c, scale);
1962 if (scale != 0) scale = ts;
1964 s = bc_num_m(c, b, &temp, scale);
1966 s = bc_num_sub(a, &temp, d, scale);
1969 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1972 bc_num_retireMul(d, ts, a->neg, b->neg);
1980 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1984 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1986 bc_num_init(&c1, len);
1987 s = bc_num_r(a, b, &c1, c, scale, ts);
1993 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1995 BcStatus s = BC_STATUS_SUCCESS;
1998 size_t i, powrdx, resrdx;
2001 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2005 return BC_STATUS_SUCCESS;
2007 else if (a->len == 0) {
2008 bc_num_setToZero(c, scale);
2009 return BC_STATUS_SUCCESS;
2011 else if (BC_NUM_ONE(b)) {
2015 s = bc_num_inv(a, c, scale);
2022 s = bc_num_ulong(b, &pow);
2025 bc_num_init(©, a->len);
2026 bc_num_copy(©, a);
2028 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2032 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2034 s = bc_num_mul(©, ©, ©, powrdx);
2038 bc_num_copy(c, ©);
2040 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2043 s = bc_num_mul(©, ©, ©, powrdx);
2048 s = bc_num_mul(c, ©, c, resrdx);
2054 s = bc_num_inv(c, c, scale);
2058 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2060 // We can't use bc_num_clean() here.
2061 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2062 if (zero) bc_num_setToZero(c, scale);
2069 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2070 BcNumBinaryOp op, size_t req)
2073 BcNum num2, *ptr_a, *ptr_b;
2078 memcpy(ptr_a, c, sizeof(BcNum));
2087 memcpy(ptr_b, c, sizeof(BcNum));
2095 bc_num_init(c, req);
2097 bc_num_expand(c, req);
2099 s = op(ptr_a, ptr_b, c, scale);
2101 if (init) bc_num_free(&num2);
2106 static bool bc_num_strValid(const char *val, size_t base)
2109 bool small, radix = false;
2110 size_t i, len = strlen(val);
2112 if (!len) return true;
2115 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2117 for (i = 0; i < len; ++i) {
2123 if (radix) return false;
2129 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2136 static void bc_num_parseDecimal(BcNum *n, const char *val)
2142 for (i = 0; val[i] == '0'; ++i);
2149 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2150 bc_num_expand(n, len);
2153 ptr = strchr(val, '.');
2155 // Explicitly test for NULL here to produce either a 0 or 1.
2156 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2159 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2160 n->num[n->len] = val[i] - '0';
2164 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2167 BcNum temp, mult, result;
2171 size_t i, digits, len = strlen(val);
2175 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2178 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2179 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2181 for (i = 0; i < len; ++i) {
2184 if (c == '.') break;
2186 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2188 s = bc_num_mul(n, base, &mult, 0);
2189 if (s) goto int_err;
2190 bc_num_ulong2num(&temp, v);
2191 s = bc_num_add(&mult, &temp, n, 0);
2192 if (s) goto int_err;
2197 if (c == 0) goto int_err;
2200 bc_num_init(&result, base->len);
2201 bc_num_zero(&result);
2204 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2209 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2211 s = bc_num_mul(&result, base, &result, 0);
2213 bc_num_ulong2num(&temp, v);
2214 s = bc_num_add(&result, &temp, &result, 0);
2216 s = bc_num_mul(&mult, base, &mult, 0);
2220 s = bc_num_div(&result, &mult, &result, digits);
2222 s = bc_num_add(n, &result, n, digits);
2226 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2232 bc_num_free(&result);
2238 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2240 if (*nchars == line_len - 1) {
2248 static void bc_num_printChar(size_t num, size_t width, bool radix,
2249 size_t *nchars, size_t line_len)
2251 (void) radix, (void) line_len;
2252 bb_putchar((char) num);
2253 *nchars = *nchars + width;
2257 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2258 size_t *nchars, size_t line_len)
2262 bc_num_printNewline(nchars, line_len);
2263 bb_putchar(radix ? '.' : ' ');
2266 bc_num_printNewline(nchars, line_len);
2267 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2270 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2272 bc_num_printNewline(nchars, line_len);
2275 bb_putchar(((char) dig) + '0');
2279 static void bc_num_printHex(size_t num, size_t width, bool radix,
2280 size_t *nchars, size_t line_len)
2283 bc_num_printNewline(nchars, line_len);
2288 bc_num_printNewline(nchars, line_len);
2289 bb_putchar(bb_hexdigits_upcase[num]);
2290 *nchars = *nchars + width;
2293 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2295 size_t i, rdx = n->rdx - 1;
2297 if (n->neg) bb_putchar('-');
2298 (*nchars) += n->neg;
2300 for (i = n->len - 1; i < n->len; --i)
2301 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2304 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2305 size_t *nchars, size_t len, BcNumDigitOp print)
2309 BcNum intp, fracp, digit, frac_len;
2310 unsigned long dig, *ptr;
2315 print(0, width, false, nchars, len);
2316 return BC_STATUS_SUCCESS;
2319 bc_vec_init(&stack, sizeof(long), NULL);
2320 bc_num_init(&intp, n->len);
2321 bc_num_init(&fracp, n->rdx);
2322 bc_num_init(&digit, width);
2323 bc_num_init(&frac_len, BC_NUM_INT(n));
2324 bc_num_copy(&intp, n);
2325 bc_num_one(&frac_len);
2327 bc_num_truncate(&intp, intp.rdx);
2328 s = bc_num_sub(n, &intp, &fracp, 0);
2331 while (intp.len != 0) {
2332 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2334 s = bc_num_ulong(&digit, &dig);
2336 bc_vec_push(&stack, &dig);
2339 for (i = 0; i < stack.len; ++i) {
2340 ptr = bc_vec_item_rev(&stack, i);
2341 print(*ptr, width, false, nchars, len);
2344 if (!n->rdx) goto err;
2346 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2347 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2349 s = bc_num_ulong(&fracp, &dig);
2351 bc_num_ulong2num(&intp, dig);
2352 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2354 print(dig, width, radix, nchars, len);
2355 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2360 bc_num_free(&frac_len);
2361 bc_num_free(&digit);
2362 bc_num_free(&fracp);
2364 bc_vec_free(&stack);
2368 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2369 size_t *nchars, size_t line_len)
2376 if (neg) bb_putchar('-');
2381 if (base_t <= BC_NUM_MAX_IBASE) {
2383 print = bc_num_printHex;
2386 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2387 print = bc_num_printDigits;
2390 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2397 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2399 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2403 static void bc_num_init(BcNum *n, size_t req)
2405 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2406 memset(n, 0, sizeof(BcNum));
2407 n->num = xmalloc(req);
2411 static void bc_num_expand(BcNum *n, size_t req)
2413 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2415 n->num = xrealloc(n->num, req);
2420 static void bc_num_free(void *num)
2422 free(((BcNum *) num)->num);
2425 static void bc_num_copy(BcNum *d, BcNum *s)
2428 bc_num_expand(d, s->cap);
2432 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2436 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2439 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2442 bc_num_parseDecimal(n, val);
2444 bc_num_parseBase(n, val, base);
2446 return BC_STATUS_SUCCESS;
2449 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2450 size_t *nchars, size_t line_len)
2452 BcStatus s = BC_STATUS_SUCCESS;
2454 bc_num_printNewline(nchars, line_len);
2460 else if (base_t == 10)
2461 bc_num_printDecimal(n, nchars, line_len);
2463 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2473 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2478 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2480 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2482 unsigned long prev = *result, powprev = pow;
2484 *result += ((unsigned long) n->num[i]) * pow;
2487 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2490 return BC_STATUS_SUCCESS;
2493 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2501 if (val == 0) return;
2503 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2504 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2507 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2509 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2511 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2514 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2516 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2518 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2521 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2523 size_t req = BC_NUM_MREQ(a, b, scale);
2524 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2527 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2529 size_t req = BC_NUM_MREQ(a, b, scale);
2530 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2533 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2535 size_t req = BC_NUM_MREQ(a, b, scale);
2536 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2539 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2541 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2544 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2547 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2548 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2549 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2551 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2552 bc_num_expand(b, req);
2555 bc_num_setToZero(b, scale);
2556 return BC_STATUS_SUCCESS;
2559 return BC_STATUS_MATH_NEGATIVE;
2560 else if (BC_NUM_ONE(a)) {
2562 bc_num_extend(b, scale);
2563 return BC_STATUS_SUCCESS;
2566 scale = BC_MAX(scale, a->rdx) + 1;
2567 len = a->len + scale;
2569 bc_num_init(&num1, len);
2570 bc_num_init(&num2, len);
2571 bc_num_init(&half, BC_NUM_DEF_SIZE);
2577 bc_num_init(&f, len);
2578 bc_num_init(&fprime, len);
2584 pow = BC_NUM_INT(a);
2593 pow -= 2 - (pow & 1);
2595 bc_num_extend(x0, pow);
2597 // Make sure to move the radix back.
2601 x0->rdx = digs = digs1 = 0;
2603 len = BC_NUM_INT(x0) + resrdx - 1;
2605 while (cmp != 0 || digs < len) {
2607 s = bc_num_div(a, x0, &f, resrdx);
2609 s = bc_num_add(x0, &f, &fprime, resrdx);
2611 s = bc_num_mul(&fprime, &half, x1, resrdx);
2614 cmp = bc_num_cmp(x1, x0);
2615 digs = x1->len - (unsigned long long) llabs(cmp);
2617 if (cmp == cmp2 && digs == digs1)
2622 resrdx += times > 4;
2635 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2638 bc_num_free(&fprime);
2646 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2652 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2655 memcpy(&num2, c, sizeof(BcNum));
2657 bc_num_init(c, len);
2662 bc_num_expand(c, len);
2665 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2667 if (init) bc_num_free(&num2);
2673 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2676 BcNum base, exp, two, temp;
2678 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2679 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2680 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2682 bc_num_expand(d, c->len);
2683 bc_num_init(&base, c->len);
2684 bc_num_init(&exp, b->len);
2685 bc_num_init(&two, BC_NUM_DEF_SIZE);
2686 bc_num_init(&temp, b->len);
2692 s = bc_num_rem(a, c, &base, 0);
2694 bc_num_copy(&exp, b);
2696 while (exp.len != 0) {
2698 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2701 if (BC_NUM_ONE(&temp)) {
2702 s = bc_num_mul(d, &base, &temp, 0);
2704 s = bc_num_rem(&temp, c, d, 0);
2708 s = bc_num_mul(&base, &base, &temp, 0);
2710 s = bc_num_rem(&temp, c, &base, 0);
2723 static int bc_id_cmp(const void *e1, const void *e2)
2725 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2728 static void bc_id_free(void *id)
2730 free(((BcId *) id)->name);
2733 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2738 for (i = 0; i < f->autos.len; ++i) {
2739 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2740 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2746 bc_vec_push(&f->autos, &a);
2748 return BC_STATUS_SUCCESS;
2751 static void bc_func_init(BcFunc *f)
2753 bc_vec_init(&f->code, sizeof(char), NULL);
2754 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2755 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2759 static void bc_func_free(void *func)
2761 BcFunc *f = (BcFunc *) func;
2762 bc_vec_free(&f->code);
2763 bc_vec_free(&f->autos);
2764 bc_vec_free(&f->labels);
2767 static void bc_array_init(BcVec *a, bool nums)
2770 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2772 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2773 bc_array_expand(a, 1);
2776 static void bc_array_copy(BcVec *d, const BcVec *s)
2780 bc_vec_npop(d, d->len);
2781 bc_vec_expand(d, s->cap);
2784 for (i = 0; i < s->len; ++i) {
2785 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2786 bc_num_init(dnum, snum->len);
2787 bc_num_copy(dnum, snum);
2791 static void bc_array_expand(BcVec *a, size_t len)
2795 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2796 while (len > a->len) {
2797 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2798 bc_vec_push(a, &data.n);
2802 while (len > a->len) {
2803 bc_array_init(&data.v, true);
2804 bc_vec_push(a, &data.v);
2809 static void bc_string_free(void *string)
2811 free(*((char **) string));
2815 static void bc_result_copy(BcResult *d, BcResult *src)
2821 case BC_RESULT_TEMP:
2822 case BC_RESULT_IBASE:
2823 case BC_RESULT_SCALE:
2824 case BC_RESULT_OBASE:
2826 bc_num_init(&d->d.n, src->d.n.len);
2827 bc_num_copy(&d->d.n, &src->d.n);
2832 case BC_RESULT_ARRAY:
2833 case BC_RESULT_ARRAY_ELEM:
2835 d->d.id.name = xstrdup(src->d.id.name);
2839 case BC_RESULT_CONSTANT:
2840 case BC_RESULT_LAST:
2844 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2851 static void bc_result_free(void *result)
2853 BcResult *r = (BcResult *) result;
2857 case BC_RESULT_TEMP:
2858 case BC_RESULT_IBASE:
2859 case BC_RESULT_SCALE:
2860 case BC_RESULT_OBASE:
2862 bc_num_free(&r->d.n);
2867 case BC_RESULT_ARRAY:
2868 case BC_RESULT_ARRAY_ELEM:
2882 static void bc_lex_lineComment(BcLex *l)
2884 l->t.t = BC_LEX_WHITESPACE;
2885 while (l->i < l->len && l->buf[l->i++] != '\n');
2889 static void bc_lex_whitespace(BcLex *l)
2892 l->t.t = BC_LEX_WHITESPACE;
2893 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2896 static BcStatus bc_lex_number(BcLex *l, char start)
2898 const char *buf = l->buf + l->i;
2899 size_t len, hits = 0, bslashes = 0, i = 0, j;
2901 bool last_pt, pt = start == '.';
2904 l->t.t = BC_LEX_NUMBER;
2906 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2907 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2921 len = i + 1 * !last_pt - bslashes * 2;
2922 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2924 bc_vec_npop(&l->t.v, l->t.v.len);
2925 bc_vec_expand(&l->t.v, len + 1);
2926 bc_vec_push(&l->t.v, &start);
2928 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2932 // If we have hit a backslash, skip it. We don't have
2933 // to check for a newline because it's guaranteed.
2934 if (hits < bslashes && c == '\\') {
2940 bc_vec_push(&l->t.v, &c);
2943 bc_vec_pushByte(&l->t.v, '\0');
2946 return BC_STATUS_SUCCESS;
2949 static BcStatus bc_lex_name(BcLex *l)
2952 const char *buf = l->buf + l->i - 1;
2955 l->t.t = BC_LEX_NAME;
2957 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2959 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2960 bc_vec_string(&l->t.v, i, buf);
2962 // Increment the index. We minus 1 because it has already been incremented.
2965 return BC_STATUS_SUCCESS;
2968 static void bc_lex_init(BcLex *l, BcLexNext next)
2971 bc_vec_init(&l->t.v, sizeof(char), NULL);
2974 static void bc_lex_free(BcLex *l)
2976 bc_vec_free(&l->t.v);
2979 static void bc_lex_file(BcLex *l, const char *file)
2986 static BcStatus bc_lex_next(BcLex *l)
2991 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
2993 l->line += l->newline;
2994 l->t.t = BC_LEX_EOF;
2996 l->newline = (l->i == l->len);
2997 if (l->newline) return BC_STATUS_SUCCESS;
2999 // Loop until failure or we don't have whitespace. This
3000 // is so the parser doesn't get inundated with whitespace.
3003 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3008 static BcStatus bc_lex_text(BcLex *l, const char *text)
3012 l->len = strlen(text);
3013 l->t.t = l->t.last = BC_LEX_INVALID;
3014 return bc_lex_next(l);
3018 static BcStatus bc_lex_identifier(BcLex *l)
3022 const char *buf = l->buf + l->i - 1;
3024 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3026 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3028 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3030 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3032 if (!bc_lex_kws[i].posix) {
3033 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3034 bc_lex_kws[i].name);
3038 // We minus 1 because the index has already been incremented.
3040 return BC_STATUS_SUCCESS;
3047 if (l->t.v.len - 1 > 1)
3048 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3053 static BcStatus bc_lex_string(BcLex *l)
3055 size_t len, nls = 0, i = l->i;
3058 l->t.t = BC_LEX_STR;
3060 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3064 return BC_STATUS_LEX_NO_STRING_END;
3068 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3069 bc_vec_string(&l->t.v, len, l->buf + l->i);
3074 return BC_STATUS_SUCCESS;
3077 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3079 if (l->buf[l->i] == '=') {
3087 static BcStatus bc_lex_comment(BcLex *l)
3090 const char *buf = l->buf;
3092 l->t.t = BC_LEX_WHITESPACE;
3105 return BC_STATUS_LEX_NO_COMMENT_END;
3114 return BC_STATUS_SUCCESS;
3117 static BcStatus bc_lex_token(BcLex *l)
3119 BcStatus s = BC_STATUS_SUCCESS;
3120 char c = l->buf[l->i++], c2;
3122 // This is the workhorse of the lexer.
3129 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3139 bc_lex_whitespace(l);
3145 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3147 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3148 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3157 s = bc_lex_string(l);
3163 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3166 bc_lex_lineComment(l);
3173 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3182 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3186 l->t.t = BC_LEX_OP_BOOL_AND;
3189 l->t.t = BC_LEX_INVALID;
3190 s = bc_error("bad character '%c'", '&');
3199 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3205 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3214 l->t.t = BC_LEX_OP_INC;
3217 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3223 l->t.t = BC_LEX_COMMA;
3232 l->t.t = BC_LEX_OP_DEC;
3235 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3241 if (isdigit(l->buf[l->i]))
3242 s = bc_lex_number(l, c);
3244 l->t.t = BC_LEX_KEY_LAST;
3245 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3254 s = bc_lex_comment(l);
3256 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3277 s = bc_lex_number(l, c);
3283 l->t.t = BC_LEX_SCOLON;
3289 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3295 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3301 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3308 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3314 if (l->buf[l->i] == '\n') {
3315 l->t.t = BC_LEX_WHITESPACE;
3319 s = bc_error("bad character '%c'", c);
3325 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3356 s = bc_lex_identifier(l);
3363 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3373 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3377 l->t.t = BC_LEX_OP_BOOL_OR;
3380 l->t.t = BC_LEX_INVALID;
3381 s = bc_error("bad character '%c'", c);
3389 l->t.t = BC_LEX_INVALID;
3390 s = bc_error("bad character '%c'", c);
3400 static BcStatus dc_lex_register(BcLex *l)
3402 BcStatus s = BC_STATUS_SUCCESS;
3404 if (isspace(l->buf[l->i - 1])) {
3405 bc_lex_whitespace(l);
3408 s = BC_STATUS_LEX_EXTENDED_REG;
3413 bc_vec_npop(&l->t.v, l->t.v.len);
3414 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3415 bc_vec_pushByte(&l->t.v, '\0');
3416 l->t.t = BC_LEX_NAME;
3422 static BcStatus dc_lex_string(BcLex *l)
3424 size_t depth = 1, nls = 0, i = l->i;
3427 l->t.t = BC_LEX_STR;
3428 bc_vec_npop(&l->t.v, l->t.v.len);
3430 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3432 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3433 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3436 if (depth) bc_vec_push(&l->t.v, &c);
3441 return BC_STATUS_LEX_NO_STRING_END;
3444 bc_vec_pushByte(&l->t.v, '\0');
3445 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3450 return BC_STATUS_SUCCESS;
3453 static BcStatus dc_lex_token(BcLex *l)
3455 BcStatus s = BC_STATUS_SUCCESS;
3456 char c = l->buf[l->i++], c2;
3459 for (i = 0; i < dc_lex_regs_len; ++i) {
3460 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3463 if (c >= '%' && c <= '~' &&
3464 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3469 // This is the workhorse of the lexer.
3474 l->t.t = BC_LEX_EOF;
3485 l->newline = (c == '\n');
3486 bc_lex_whitespace(l);
3495 l->t.t = BC_LEX_OP_REL_NE;
3497 l->t.t = BC_LEX_OP_REL_LE;
3499 l->t.t = BC_LEX_OP_REL_GE;
3501 return bc_error("bad character '%c'", c);
3509 bc_lex_lineComment(l);
3515 if (isdigit(l->buf[l->i]))
3516 s = bc_lex_number(l, c);
3518 s = bc_error("bad character '%c'", c);
3539 s = bc_lex_number(l, c);
3545 s = dc_lex_string(l);
3551 l->t.t = BC_LEX_INVALID;
3552 s = bc_error("bad character '%c'", c);
3561 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3563 bc_program_addFunc(name, idx);
3564 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3567 static void bc_parse_pushName(BcParse *p, char *name)
3569 size_t i = 0, len = strlen(name);
3571 for (; i < len; ++i) bc_parse_push(p, name[i]);
3572 bc_parse_push(p, BC_PARSE_STREND);
3577 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3579 unsigned char amt, i, nums[sizeof(size_t)];
3581 for (amt = 0; idx; ++amt) {
3582 nums[amt] = (char) idx;
3583 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3586 bc_parse_push(p, amt);
3587 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3590 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3592 char *num = xstrdup(p->l.t.v.v);
3593 size_t idx = G.prog.consts.len;
3595 bc_vec_push(&G.prog.consts, &num);
3597 bc_parse_push(p, BC_INST_NUM);
3598 bc_parse_pushIndex(p, idx);
3601 (*prev) = BC_INST_NUM;
3604 static BcStatus bc_parse_text(BcParse *p, const char *text)
3608 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3610 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3611 p->l.t.t = BC_LEX_INVALID;
3614 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3617 return bc_lex_text(&p->l, text);
3620 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3622 if (p->fidx != BC_PROG_MAIN) {
3624 p->func->nparams = 0;
3625 bc_vec_npop(&p->func->code, p->func->code.len);
3626 bc_vec_npop(&p->func->autos, p->func->autos.len);
3627 bc_vec_npop(&p->func->labels, p->func->labels.len);
3629 bc_parse_updateFunc(p, BC_PROG_MAIN);
3633 p->l.t.t = BC_LEX_EOF;
3634 p->auto_part = (p->nbraces = 0);
3636 bc_vec_npop(&p->flags, p->flags.len - 1);
3637 bc_vec_npop(&p->exits, p->exits.len);
3638 bc_vec_npop(&p->conds, p->conds.len);
3639 bc_vec_npop(&p->ops, p->ops.len);
3641 return bc_program_reset(s);
3644 static void bc_parse_free(BcParse *p)
3646 bc_vec_free(&p->flags);
3647 bc_vec_free(&p->exits);
3648 bc_vec_free(&p->conds);
3649 bc_vec_free(&p->ops);
3653 static void bc_parse_create(BcParse *p, size_t func,
3654 BcParseParse parse, BcLexNext next)
3656 memset(p, 0, sizeof(BcParse));
3658 bc_lex_init(&p->l, next);
3659 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3660 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3661 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3662 bc_vec_pushByte(&p->flags, 0);
3663 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3666 // p->auto_part = p->nbraces = 0; - already is
3667 bc_parse_updateFunc(p, func);
3671 static BcStatus bc_parse_else(BcParse *p);
3672 static BcStatus bc_parse_stmt(BcParse *p);
3674 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3675 size_t *nexprs, bool next)
3677 BcStatus s = BC_STATUS_SUCCESS;
3679 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3680 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3682 while (p->ops.len > start) {
3684 t = BC_PARSE_TOP_OP(p);
3685 if (t == BC_LEX_LPAREN) break;
3687 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3688 if (l >= r && (l != r || !left)) break;
3690 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3691 bc_vec_pop(&p->ops);
3692 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3695 bc_vec_push(&p->ops, &type);
3696 if (next) s = bc_lex_next(&p->l);
3701 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3705 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3706 top = BC_PARSE_TOP_OP(p);
3708 while (top != BC_LEX_LPAREN) {
3710 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3712 bc_vec_pop(&p->ops);
3713 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3715 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3716 top = BC_PARSE_TOP_OP(p);
3719 bc_vec_pop(&p->ops);
3721 return bc_lex_next(&p->l);
3724 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3730 s = bc_lex_next(&p->l);
3733 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3735 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3736 s = bc_parse_expr(p, flags, bc_parse_next_param);
3739 comma = p->l.t.t == BC_LEX_COMMA;
3741 s = bc_lex_next(&p->l);
3746 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3747 bc_parse_push(p, BC_INST_CALL);
3748 bc_parse_pushIndex(p, nparams);
3750 return BC_STATUS_SUCCESS;
3753 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3756 BcId entry, *entry_ptr;
3761 s = bc_parse_params(p, flags);
3764 if (p->l.t.t != BC_LEX_RPAREN) {
3765 s = BC_STATUS_PARSE_BAD_TOKEN;
3769 idx = bc_map_index(&G.prog.fn_map, &entry);
3771 if (idx == BC_VEC_INVALID_IDX) {
3772 name = xstrdup(entry.name);
3773 bc_parse_addFunc(p, name, &idx);
3774 idx = bc_map_index(&G.prog.fn_map, &entry);
3780 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3781 bc_parse_pushIndex(p, entry_ptr->idx);
3783 return bc_lex_next(&p->l);
3790 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3795 name = xstrdup(p->l.t.v.v);
3796 s = bc_lex_next(&p->l);
3799 if (p->l.t.t == BC_LEX_LBRACKET) {
3801 s = bc_lex_next(&p->l);
3804 if (p->l.t.t == BC_LEX_RBRACKET) {
3806 if (!(flags & BC_PARSE_ARRAY)) {
3807 s = BC_STATUS_PARSE_BAD_EXP;
3811 *type = BC_INST_ARRAY;
3815 *type = BC_INST_ARRAY_ELEM;
3817 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3818 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3822 s = bc_lex_next(&p->l);
3824 bc_parse_push(p, *type);
3825 bc_parse_pushName(p, name);
3827 else if (p->l.t.t == BC_LEX_LPAREN) {
3829 if (flags & BC_PARSE_NOCALL) {
3830 s = BC_STATUS_PARSE_BAD_TOKEN;
3834 *type = BC_INST_CALL;
3835 s = bc_parse_call(p, name, flags);
3838 *type = BC_INST_VAR;
3839 bc_parse_push(p, BC_INST_VAR);
3840 bc_parse_pushName(p, name);
3850 static BcStatus bc_parse_read(BcParse *p)
3854 s = bc_lex_next(&p->l);
3856 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3858 s = bc_lex_next(&p->l);
3860 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3862 bc_parse_push(p, BC_INST_READ);
3864 return bc_lex_next(&p->l);
3867 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3872 s = bc_lex_next(&p->l);
3874 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3876 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3878 s = bc_lex_next(&p->l);
3881 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3884 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3886 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3887 bc_parse_push(p, *prev);
3889 return bc_lex_next(&p->l);
3892 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3896 s = bc_lex_next(&p->l);
3899 if (p->l.t.t != BC_LEX_LPAREN) {
3900 *type = BC_INST_SCALE;
3901 bc_parse_push(p, BC_INST_SCALE);
3902 return BC_STATUS_SUCCESS;
3905 *type = BC_INST_SCALE_FUNC;
3906 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3908 s = bc_lex_next(&p->l);
3911 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3913 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3914 bc_parse_push(p, BC_INST_SCALE_FUNC);
3916 return bc_lex_next(&p->l);
3919 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3920 size_t *nexprs, uint8_t flags)
3925 BcInst etype = *prev;
3927 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3928 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3929 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3931 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3932 bc_parse_push(p, inst);
3933 s = bc_lex_next(&p->l);
3937 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3940 s = bc_lex_next(&p->l);
3944 // Because we parse the next part of the expression
3945 // right here, we need to increment this.
3946 *nexprs = *nexprs + 1;
3952 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3956 case BC_LEX_KEY_IBASE:
3957 case BC_LEX_KEY_LAST:
3958 case BC_LEX_KEY_OBASE:
3960 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3961 s = bc_lex_next(&p->l);
3965 case BC_LEX_KEY_SCALE:
3967 s = bc_lex_next(&p->l);
3969 if (p->l.t.t == BC_LEX_LPAREN)
3970 s = BC_STATUS_PARSE_BAD_TOKEN;
3972 bc_parse_push(p, BC_INST_SCALE);
3978 s = BC_STATUS_PARSE_BAD_TOKEN;
3983 if (!s) bc_parse_push(p, inst);
3989 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3990 bool rparen, size_t *nexprs)
3994 BcInst etype = *prev;
3996 s = bc_lex_next(&p->l);
3999 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4000 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4003 *prev = BC_PARSE_TOKEN_INST(type);
4005 // We can just push onto the op stack because this is the largest
4006 // precedence operator that gets pushed. Inc/dec does not.
4007 if (type != BC_LEX_OP_MINUS)
4008 bc_vec_push(&p->ops, &type);
4010 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4015 static BcStatus bc_parse_string(BcParse *p, char inst)
4017 char *str = xstrdup(p->l.t.v.v);
4019 bc_parse_push(p, BC_INST_STR);
4020 bc_parse_pushIndex(p, G.prog.strs.len);
4021 bc_vec_push(&G.prog.strs, &str);
4022 bc_parse_push(p, inst);
4024 return bc_lex_next(&p->l);
4027 static BcStatus bc_parse_print(BcParse *p)
4033 s = bc_lex_next(&p->l);
4038 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4039 return BC_STATUS_PARSE_BAD_PRINT;
4041 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4043 if (type == BC_LEX_STR)
4044 s = bc_parse_string(p, BC_INST_PRINT_POP);
4046 s = bc_parse_expr(p, 0, bc_parse_next_print);
4048 bc_parse_push(p, BC_INST_PRINT_POP);
4053 comma = p->l.t.t == BC_LEX_COMMA;
4054 if (comma) s = bc_lex_next(&p->l);
4059 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4061 return bc_lex_next(&p->l);
4064 static BcStatus bc_parse_return(BcParse *p)
4070 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4072 s = bc_lex_next(&p->l);
4076 paren = t == BC_LEX_LPAREN;
4078 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4079 bc_parse_push(p, BC_INST_RET0);
4082 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4083 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4085 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4086 bc_parse_push(p, BC_INST_RET0);
4087 s = bc_lex_next(&p->l);
4091 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4092 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4096 bc_parse_push(p, BC_INST_RET);
4102 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4104 BcStatus s = BC_STATUS_SUCCESS;
4106 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4107 return BC_STATUS_PARSE_BAD_TOKEN;
4111 if (p->l.t.t == BC_LEX_RBRACE) {
4112 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4114 s = bc_lex_next(&p->l);
4118 return BC_STATUS_PARSE_BAD_TOKEN;
4121 if (BC_PARSE_IF(p)) {
4125 while (p->l.t.t == BC_LEX_NLINE) {
4126 s = bc_lex_next(&p->l);
4130 bc_vec_pop(&p->flags);
4132 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4133 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4135 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4137 else if (BC_PARSE_ELSE(p)) {
4142 bc_vec_pop(&p->flags);
4144 ip = bc_vec_top(&p->exits);
4145 label = bc_vec_item(&p->func->labels, ip->idx);
4146 *label = p->func->code.len;
4148 bc_vec_pop(&p->exits);
4150 else if (BC_PARSE_FUNC_INNER(p)) {
4151 bc_parse_push(p, BC_INST_RET0);
4152 bc_parse_updateFunc(p, BC_PROG_MAIN);
4153 bc_vec_pop(&p->flags);
4157 BcInstPtr *ip = bc_vec_top(&p->exits);
4158 size_t *label = bc_vec_top(&p->conds);
4160 bc_parse_push(p, BC_INST_JUMP);
4161 bc_parse_pushIndex(p, *label);
4163 label = bc_vec_item(&p->func->labels, ip->idx);
4164 *label = p->func->code.len;
4166 bc_vec_pop(&p->flags);
4167 bc_vec_pop(&p->exits);
4168 bc_vec_pop(&p->conds);
4174 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4176 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4177 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4178 flags |= BC_PARSE_FLAG_BODY;
4179 bc_vec_push(&p->flags, &flags);
4182 static void bc_parse_noElse(BcParse *p)
4186 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4188 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4190 ip = bc_vec_top(&p->exits);
4191 label = bc_vec_item(&p->func->labels, ip->idx);
4192 *label = p->func->code.len;
4194 bc_vec_pop(&p->exits);
4197 static BcStatus bc_parse_if(BcParse *p)
4202 s = bc_lex_next(&p->l);
4204 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4206 s = bc_lex_next(&p->l);
4208 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4210 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4212 s = bc_lex_next(&p->l);
4214 bc_parse_push(p, BC_INST_JUMP_ZERO);
4216 ip.idx = p->func->labels.len;
4217 ip.func = ip.len = 0;
4219 bc_parse_pushIndex(p, ip.idx);
4220 bc_vec_push(&p->exits, &ip);
4221 bc_vec_push(&p->func->labels, &ip.idx);
4222 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4224 return BC_STATUS_SUCCESS;
4227 static BcStatus bc_parse_else(BcParse *p)
4231 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4233 ip.idx = p->func->labels.len;
4234 ip.func = ip.len = 0;
4236 bc_parse_push(p, BC_INST_JUMP);
4237 bc_parse_pushIndex(p, ip.idx);
4241 bc_vec_push(&p->exits, &ip);
4242 bc_vec_push(&p->func->labels, &ip.idx);
4243 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4245 return bc_lex_next(&p->l);
4248 static BcStatus bc_parse_while(BcParse *p)
4253 s = bc_lex_next(&p->l);
4255 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4256 s = bc_lex_next(&p->l);
4259 ip.idx = p->func->labels.len;
4261 bc_vec_push(&p->func->labels, &p->func->code.len);
4262 bc_vec_push(&p->conds, &ip.idx);
4264 ip.idx = p->func->labels.len;
4268 bc_vec_push(&p->exits, &ip);
4269 bc_vec_push(&p->func->labels, &ip.idx);
4271 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4273 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4274 s = bc_lex_next(&p->l);
4277 bc_parse_push(p, BC_INST_JUMP_ZERO);
4278 bc_parse_pushIndex(p, ip.idx);
4279 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4281 return BC_STATUS_SUCCESS;
4284 static BcStatus bc_parse_for(BcParse *p)
4288 size_t cond_idx, exit_idx, body_idx, update_idx;
4290 s = bc_lex_next(&p->l);
4292 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4293 s = bc_lex_next(&p->l);
4296 if (p->l.t.t != BC_LEX_SCOLON)
4297 s = bc_parse_expr(p, 0, bc_parse_next_for);
4299 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4302 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4303 s = bc_lex_next(&p->l);
4306 cond_idx = p->func->labels.len;
4307 update_idx = cond_idx + 1;
4308 body_idx = update_idx + 1;
4309 exit_idx = body_idx + 1;
4311 bc_vec_push(&p->func->labels, &p->func->code.len);
4313 if (p->l.t.t != BC_LEX_SCOLON)
4314 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4316 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4319 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4321 s = bc_lex_next(&p->l);
4324 bc_parse_push(p, BC_INST_JUMP_ZERO);
4325 bc_parse_pushIndex(p, exit_idx);
4326 bc_parse_push(p, BC_INST_JUMP);
4327 bc_parse_pushIndex(p, body_idx);
4329 ip.idx = p->func->labels.len;
4331 bc_vec_push(&p->conds, &update_idx);
4332 bc_vec_push(&p->func->labels, &p->func->code.len);
4334 if (p->l.t.t != BC_LEX_RPAREN)
4335 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4337 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4341 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4342 bc_parse_push(p, BC_INST_JUMP);
4343 bc_parse_pushIndex(p, cond_idx);
4344 bc_vec_push(&p->func->labels, &p->func->code.len);
4350 bc_vec_push(&p->exits, &ip);
4351 bc_vec_push(&p->func->labels, &ip.idx);
4353 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4355 return BC_STATUS_SUCCESS;
4358 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4364 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4366 if (type == BC_LEX_KEY_BREAK) {
4368 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4370 i = p->exits.len - 1;
4371 ip = bc_vec_item(&p->exits, i);
4373 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4374 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4379 i = *((size_t *) bc_vec_top(&p->conds));
4381 bc_parse_push(p, BC_INST_JUMP);
4382 bc_parse_pushIndex(p, i);
4384 s = bc_lex_next(&p->l);
4387 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4388 return BC_STATUS_PARSE_BAD_TOKEN;
4390 return bc_lex_next(&p->l);
4393 static BcStatus bc_parse_func(BcParse *p)
4396 bool var, comma = false;
4400 s = bc_lex_next(&p->l);
4402 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4404 name = xstrdup(p->l.t.v.v);
4405 bc_parse_addFunc(p, name, &p->fidx);
4407 s = bc_lex_next(&p->l);
4409 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4410 s = bc_lex_next(&p->l);
4413 while (p->l.t.t != BC_LEX_RPAREN) {
4415 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4419 name = xstrdup(p->l.t.v.v);
4420 s = bc_lex_next(&p->l);
4423 var = p->l.t.t != BC_LEX_LBRACKET;
4427 s = bc_lex_next(&p->l);
4430 if (p->l.t.t != BC_LEX_RBRACKET) {
4431 s = BC_STATUS_PARSE_BAD_FUNC;
4435 s = bc_lex_next(&p->l);
4439 comma = p->l.t.t == BC_LEX_COMMA;
4441 s = bc_lex_next(&p->l);
4445 s = bc_func_insert(p->func, name, var);
4449 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4451 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4452 bc_parse_startBody(p, flags);
4454 s = bc_lex_next(&p->l);
4457 if (p->l.t.t != BC_LEX_LBRACE)
4458 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4467 static BcStatus bc_parse_auto(BcParse *p)
4470 bool comma, var, one;
4473 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4474 s = bc_lex_next(&p->l);
4477 p->auto_part = comma = false;
4478 one = p->l.t.t == BC_LEX_NAME;
4480 while (p->l.t.t == BC_LEX_NAME) {
4482 name = xstrdup(p->l.t.v.v);
4483 s = bc_lex_next(&p->l);
4486 var = p->l.t.t != BC_LEX_LBRACKET;
4489 s = bc_lex_next(&p->l);
4492 if (p->l.t.t != BC_LEX_RBRACKET) {
4493 s = BC_STATUS_PARSE_BAD_FUNC;
4497 s = bc_lex_next(&p->l);
4501 comma = p->l.t.t == BC_LEX_COMMA;
4503 s = bc_lex_next(&p->l);
4507 s = bc_func_insert(p->func, name, var);
4511 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4512 if (!one) return bc_error("no auto variable found");
4514 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4515 return BC_STATUS_PARSE_BAD_TOKEN;
4517 return bc_lex_next(&p->l);
4524 static BcStatus bc_parse_body(BcParse *p, bool brace)
4526 BcStatus s = BC_STATUS_SUCCESS;
4527 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4529 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4531 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4533 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4534 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4536 if (!p->auto_part) {
4537 s = bc_parse_auto(p);
4541 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4544 s = bc_parse_stmt(p);
4545 if (!s && !brace) s = bc_parse_endBody(p, false);
4551 static BcStatus bc_parse_stmt(BcParse *p)
4553 BcStatus s = BC_STATUS_SUCCESS;
4559 return bc_lex_next(&p->l);
4562 case BC_LEX_KEY_ELSE:
4564 p->auto_part = false;
4570 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4573 s = bc_lex_next(&p->l);
4576 return bc_parse_body(p, true);
4579 case BC_LEX_KEY_AUTO:
4581 return bc_parse_auto(p);
4586 p->auto_part = false;
4588 if (BC_PARSE_IF_END(p)) {
4590 return BC_STATUS_SUCCESS;
4592 else if (BC_PARSE_BODY(p))
4593 return bc_parse_body(p, false);
4603 case BC_LEX_OP_MINUS:
4604 case BC_LEX_OP_BOOL_NOT:
4608 case BC_LEX_KEY_IBASE:
4609 case BC_LEX_KEY_LAST:
4610 case BC_LEX_KEY_LENGTH:
4611 case BC_LEX_KEY_OBASE:
4612 case BC_LEX_KEY_READ:
4613 case BC_LEX_KEY_SCALE:
4614 case BC_LEX_KEY_SQRT:
4616 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4620 case BC_LEX_KEY_ELSE:
4622 s = bc_parse_else(p);
4628 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4634 s = bc_parse_endBody(p, true);
4640 s = bc_parse_string(p, BC_INST_PRINT_STR);
4644 case BC_LEX_KEY_BREAK:
4645 case BC_LEX_KEY_CONTINUE:
4647 s = bc_parse_loopExit(p, p->l.t.t);
4651 case BC_LEX_KEY_FOR:
4653 s = bc_parse_for(p);
4657 case BC_LEX_KEY_HALT:
4659 bc_parse_push(p, BC_INST_HALT);
4660 s = bc_lex_next(&p->l);
4670 case BC_LEX_KEY_LIMITS:
4672 // "limits" is a compile-time command,
4673 // the output is produced at _parse time_.
4674 s = bc_lex_next(&p->l);
4676 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4677 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4678 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4679 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4680 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4681 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4682 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4683 printf("Number of vars = %lu\n", BC_MAX_VARS);
4687 case BC_LEX_KEY_PRINT:
4689 s = bc_parse_print(p);
4693 case BC_LEX_KEY_QUIT:
4695 // "quit" is a compile-time command. For example,
4696 // "if (0 == 1) quit" terminates when parsing the statement,
4697 // not when it is executed
4701 case BC_LEX_KEY_RETURN:
4703 s = bc_parse_return(p);
4707 case BC_LEX_KEY_WHILE:
4709 s = bc_parse_while(p);
4715 s = BC_STATUS_PARSE_BAD_TOKEN;
4723 static BcStatus bc_parse_parse(BcParse *p)
4727 if (p->l.t.t == BC_LEX_EOF)
4728 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4729 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4730 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4731 s = bc_parse_func(p);
4734 s = bc_parse_stmt(p);
4736 if (s || G_interrupt)
4737 s = bc_parse_reset(p, s);
4742 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4744 BcStatus s = BC_STATUS_SUCCESS;
4745 BcInst prev = BC_INST_PRINT;
4746 BcLexType top, t = p->l.t.t;
4747 size_t nexprs = 0, ops_bgn = p->ops.len;
4748 uint32_t i, nparens, nrelops;
4749 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4751 paren_first = p->l.t.t == BC_LEX_LPAREN;
4752 nparens = nrelops = 0;
4753 paren_expr = rprn = done = get_token = assign = false;
4756 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4762 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4763 rprn = get_token = bin_last = false;
4767 case BC_LEX_OP_MINUS:
4769 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4770 rprn = get_token = false;
4771 bin_last = prev == BC_INST_MINUS;
4775 case BC_LEX_OP_ASSIGN_POWER:
4776 case BC_LEX_OP_ASSIGN_MULTIPLY:
4777 case BC_LEX_OP_ASSIGN_DIVIDE:
4778 case BC_LEX_OP_ASSIGN_MODULUS:
4779 case BC_LEX_OP_ASSIGN_PLUS:
4780 case BC_LEX_OP_ASSIGN_MINUS:
4781 case BC_LEX_OP_ASSIGN:
4783 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4784 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4785 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4787 s = BC_STATUS_PARSE_BAD_ASSIGN;
4792 case BC_LEX_OP_POWER:
4793 case BC_LEX_OP_MULTIPLY:
4794 case BC_LEX_OP_DIVIDE:
4795 case BC_LEX_OP_MODULUS:
4796 case BC_LEX_OP_PLUS:
4797 case BC_LEX_OP_REL_EQ:
4798 case BC_LEX_OP_REL_LE:
4799 case BC_LEX_OP_REL_GE:
4800 case BC_LEX_OP_REL_NE:
4801 case BC_LEX_OP_REL_LT:
4802 case BC_LEX_OP_REL_GT:
4803 case BC_LEX_OP_BOOL_NOT:
4804 case BC_LEX_OP_BOOL_OR:
4805 case BC_LEX_OP_BOOL_AND:
4807 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4808 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4810 return BC_STATUS_PARSE_BAD_EXP;
4813 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4814 prev = BC_PARSE_TOKEN_INST(t);
4815 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4816 rprn = get_token = false;
4817 bin_last = t != BC_LEX_OP_BOOL_NOT;
4824 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4827 paren_expr = rprn = bin_last = false;
4829 bc_vec_push(&p->ops, &t);
4836 if (bin_last || prev == BC_INST_BOOL_NOT)
4837 return BC_STATUS_PARSE_BAD_EXP;
4840 s = BC_STATUS_SUCCESS;
4845 else if (!paren_expr)
4846 return BC_STATUS_PARSE_EMPTY_EXP;
4849 paren_expr = rprn = true;
4850 get_token = bin_last = false;
4852 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4859 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4862 rprn = get_token = bin_last = false;
4863 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4871 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4873 bc_parse_number(p, &prev, &nexprs);
4874 paren_expr = get_token = true;
4875 rprn = bin_last = false;
4880 case BC_LEX_KEY_IBASE:
4881 case BC_LEX_KEY_LAST:
4882 case BC_LEX_KEY_OBASE:
4884 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4886 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4887 bc_parse_push(p, (char) prev);
4889 paren_expr = get_token = true;
4890 rprn = bin_last = false;
4896 case BC_LEX_KEY_LENGTH:
4897 case BC_LEX_KEY_SQRT:
4899 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4901 s = bc_parse_builtin(p, t, flags, &prev);
4903 rprn = get_token = bin_last = false;
4909 case BC_LEX_KEY_READ:
4911 if (BC_PARSE_LEAF(prev, rprn))
4912 return BC_STATUS_PARSE_BAD_EXP;
4913 else if (flags & BC_PARSE_NOREAD)
4914 s = BC_STATUS_EXEC_REC_READ;
4916 s = bc_parse_read(p);
4919 rprn = get_token = bin_last = false;
4921 prev = BC_INST_READ;
4926 case BC_LEX_KEY_SCALE:
4928 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4930 s = bc_parse_scale(p, &prev, flags);
4932 rprn = get_token = bin_last = false;
4934 prev = BC_INST_SCALE;
4941 s = BC_STATUS_PARSE_BAD_TOKEN;
4946 if (!s && get_token) s = bc_lex_next(&p->l);
4950 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4952 while (p->ops.len > ops_bgn) {
4954 top = BC_PARSE_TOP_OP(p);
4955 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4957 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4958 return BC_STATUS_PARSE_BAD_EXP;
4960 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4962 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4963 bc_vec_pop(&p->ops);
4966 s = BC_STATUS_PARSE_BAD_EXP;
4967 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4969 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4972 if (!(flags & BC_PARSE_REL) && nrelops) {
4973 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4976 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4977 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4981 if (flags & BC_PARSE_PRINT) {
4982 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4983 bc_parse_push(p, BC_INST_POP);
4989 static void bc_parse_init(BcParse *p, size_t func)
4991 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4994 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4996 return bc_parse_expr(p, flags, bc_parse_next_read);
5001 static BcStatus dc_parse_register(BcParse *p)
5006 s = bc_lex_next(&p->l);
5008 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5010 name = xstrdup(p->l.t.v.v);
5011 bc_parse_pushName(p, name);
5016 static BcStatus dc_parse_string(BcParse *p)
5018 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5019 size_t idx, len = G.prog.strs.len;
5021 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5024 str = xstrdup(p->l.t.v.v);
5025 bc_parse_push(p, BC_INST_STR);
5026 bc_parse_pushIndex(p, len);
5027 bc_vec_push(&G.prog.strs, &str);
5028 bc_parse_addFunc(p, name, &idx);
5030 return bc_lex_next(&p->l);
5033 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5037 bc_parse_push(p, inst);
5039 s = dc_parse_register(p);
5044 bc_parse_push(p, BC_INST_SWAP);
5045 bc_parse_push(p, BC_INST_ASSIGN);
5046 bc_parse_push(p, BC_INST_POP);
5049 return bc_lex_next(&p->l);
5052 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5056 bc_parse_push(p, inst);
5057 bc_parse_push(p, BC_INST_EXEC_COND);
5059 s = dc_parse_register(p);
5062 s = bc_lex_next(&p->l);
5065 if (p->l.t.t == BC_LEX_ELSE) {
5066 s = dc_parse_register(p);
5068 s = bc_lex_next(&p->l);
5071 bc_parse_push(p, BC_PARSE_STREND);
5076 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5078 BcStatus s = BC_STATUS_SUCCESS;
5081 bool assign, get_token = false;
5085 case BC_LEX_OP_REL_EQ:
5086 case BC_LEX_OP_REL_LE:
5087 case BC_LEX_OP_REL_GE:
5088 case BC_LEX_OP_REL_NE:
5089 case BC_LEX_OP_REL_LT:
5090 case BC_LEX_OP_REL_GT:
5092 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5099 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5105 s = dc_parse_string(p);
5112 if (t == BC_LEX_NEG) {
5113 s = bc_lex_next(&p->l);
5115 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5118 bc_parse_number(p, &prev, &p->nbraces);
5120 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5126 case BC_LEX_KEY_READ:
5128 if (flags & BC_PARSE_NOREAD)
5129 s = BC_STATUS_EXEC_REC_READ;
5131 bc_parse_push(p, BC_INST_READ);
5136 case BC_LEX_OP_ASSIGN:
5137 case BC_LEX_STORE_PUSH:
5139 assign = t == BC_LEX_OP_ASSIGN;
5140 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5141 s = dc_parse_mem(p, inst, true, assign);
5146 case BC_LEX_LOAD_POP:
5148 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5149 s = dc_parse_mem(p, inst, true, false);
5153 case BC_LEX_STORE_IBASE:
5154 case BC_LEX_STORE_SCALE:
5155 case BC_LEX_STORE_OBASE:
5157 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5158 s = dc_parse_mem(p, inst, false, true);
5164 s = BC_STATUS_PARSE_BAD_TOKEN;
5170 if (!s && get_token) s = bc_lex_next(&p->l);
5175 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5177 BcStatus s = BC_STATUS_SUCCESS;
5181 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5183 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5185 inst = dc_parse_insts[t];
5187 if (inst != BC_INST_INVALID) {
5188 bc_parse_push(p, inst);
5189 s = bc_lex_next(&p->l);
5192 s = dc_parse_token(p, t, flags);
5195 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5196 bc_parse_push(p, BC_INST_POP_EXEC);
5201 static BcStatus dc_parse_parse(BcParse *p)
5205 if (p->l.t.t == BC_LEX_EOF)
5206 s = BC_STATUS_LEX_EOF;
5208 s = dc_parse_expr(p, 0);
5210 if (s || G_interrupt) s = bc_parse_reset(p, s);
5215 static void dc_parse_init(BcParse *p, size_t func)
5217 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5221 static void common_parse_init(BcParse *p, size_t func)
5224 bc_parse_init(p, func);
5226 dc_parse_init(p, func);
5230 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5233 return bc_parse_expression(p, flags);
5235 return dc_parse_expr(p, flags);
5239 static BcVec* bc_program_search(char *id, bool var)
5247 v = var ? &G.prog.vars : &G.prog.arrs;
5248 map = var ? &G.prog.var_map : &G.prog.arr_map;
5252 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5255 bc_array_init(&data.v, var);
5256 bc_vec_push(v, &data.v);
5259 ptr = bc_vec_item(map, i);
5260 if (new) ptr->name = xstrdup(e.name);
5261 return bc_vec_item(v, ptr->idx);
5264 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5266 BcStatus s = BC_STATUS_SUCCESS;
5271 case BC_RESULT_TEMP:
5272 case BC_RESULT_IBASE:
5273 case BC_RESULT_SCALE:
5274 case BC_RESULT_OBASE:
5280 case BC_RESULT_CONSTANT:
5282 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5283 size_t base_t, len = strlen(*str);
5286 bc_num_init(&r->d.n, len);
5288 hex = hex && len == 1;
5289 base = hex ? &G.prog.hexb : &G.prog.ib;
5290 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5291 s = bc_num_parse(&r->d.n, *str, base, base_t);
5294 bc_num_free(&r->d.n);
5299 r->t = BC_RESULT_TEMP;
5305 case BC_RESULT_ARRAY:
5306 case BC_RESULT_ARRAY_ELEM:
5310 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5312 if (r->t == BC_RESULT_ARRAY_ELEM) {
5314 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5315 *num = bc_vec_item(v, r->d.id.idx);
5318 *num = bc_vec_top(v);
5323 case BC_RESULT_LAST:
5325 *num = &G.prog.last;
5339 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5340 BcResult **r, BcNum **rn, bool assign)
5344 BcResultType lt, rt;
5346 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5348 *r = bc_vec_item_rev(&G.prog.results, 0);
5349 *l = bc_vec_item_rev(&G.prog.results, 1);
5353 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5355 s = bc_program_num(*l, ln, false);
5357 s = bc_program_num(*r, rn, hex);
5360 // We run this again under these conditions in case any vector has been
5361 // reallocated out from under the BcNums or arrays we had.
5362 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5363 s = bc_program_num(*l, ln, false);
5367 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5368 return BC_STATUS_EXEC_BAD_TYPE;
5369 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5374 static void bc_program_binOpRetire(BcResult *r)
5376 r->t = BC_RESULT_TEMP;
5377 bc_vec_pop(&G.prog.results);
5378 bc_vec_pop(&G.prog.results);
5379 bc_vec_push(&G.prog.results, r);
5382 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5386 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5387 *r = bc_vec_top(&G.prog.results);
5389 s = bc_program_num(*r, n, false);
5392 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5397 static void bc_program_retire(BcResult *r, BcResultType t)
5400 bc_vec_pop(&G.prog.results);
5401 bc_vec_push(&G.prog.results, r);
5404 static BcStatus bc_program_op(char inst)
5407 BcResult *opd1, *opd2, res;
5408 BcNum *n1, *n2 = NULL;
5410 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5412 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5414 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5416 bc_program_binOpRetire(&res);
5421 bc_num_free(&res.d.n);
5425 static BcStatus bc_program_read(void)
5432 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5434 for (i = 0; i < G.prog.stack.len; ++i) {
5435 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5436 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5439 bc_vec_npop(&f->code, f->code.len);
5440 bc_vec_init(&buf, sizeof(char), NULL);
5442 s = bc_read_line(&buf, "read> ");
5445 common_parse_init(&parse, BC_PROG_READ);
5446 bc_lex_file(&parse.l, bc_program_stdin_name);
5448 s = bc_parse_text(&parse, buf.v);
5449 if (s) goto exec_err;
5450 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5451 if (s) goto exec_err;
5453 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5454 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5458 ip.func = BC_PROG_READ;
5460 ip.len = G.prog.results.len;
5462 // Update this pointer, just in case.
5463 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5465 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5466 bc_vec_push(&G.prog.stack, &ip);
5469 bc_parse_free(&parse);
5475 static size_t bc_program_index(char *code, size_t *bgn)
5477 char amt = code[(*bgn)++], i = 0;
5480 for (; i < amt; ++i, ++(*bgn))
5481 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5486 static char *bc_program_name(char *code, size_t *bgn)
5489 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5491 s = xmalloc(ptr - str + 1);
5494 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5502 static void bc_program_printString(const char *str, size_t *nchars)
5504 size_t i, len = strlen(str);
5513 for (i = 0; i < len; ++i, ++(*nchars)) {
5517 if (c != '\\' || i == len - 1)
5577 // Just print the backslash and following character.
5588 static BcStatus bc_program_print(char inst, size_t idx)
5590 BcStatus s = BC_STATUS_SUCCESS;
5595 bool pop = inst != BC_INST_PRINT;
5597 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5599 r = bc_vec_item_rev(&G.prog.results, idx);
5600 s = bc_program_num(r, &num, false);
5603 if (BC_PROG_NUM(r, num)) {
5604 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5605 if (!s) bc_num_copy(&G.prog.last, num);
5609 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5610 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5612 if (inst == BC_INST_PRINT_STR) {
5613 for (i = 0, len = strlen(str); i < len; ++i) {
5616 if (c == '\n') G.prog.nchars = SIZE_MAX;
5621 bc_program_printString(str, &G.prog.nchars);
5622 if (inst == BC_INST_PRINT) bb_putchar('\n');
5626 if (!s && pop) bc_vec_pop(&G.prog.results);
5631 static BcStatus bc_program_negate(void)
5637 s = bc_program_prep(&ptr, &num);
5640 bc_num_init(&res.d.n, num->len);
5641 bc_num_copy(&res.d.n, num);
5642 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5644 bc_program_retire(&res, BC_RESULT_TEMP);
5649 static BcStatus bc_program_logical(char inst)
5652 BcResult *opd1, *opd2, res;
5657 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5659 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5661 if (inst == BC_INST_BOOL_AND)
5662 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5663 else if (inst == BC_INST_BOOL_OR)
5664 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5667 cmp = bc_num_cmp(n1, n2);
5671 case BC_INST_REL_EQ:
5677 case BC_INST_REL_LE:
5683 case BC_INST_REL_GE:
5689 case BC_INST_REL_NE:
5695 case BC_INST_REL_LT:
5701 case BC_INST_REL_GT:
5709 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5711 bc_program_binOpRetire(&res);
5717 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5723 memset(&n2, 0, sizeof(BcNum));
5724 n2.rdx = res.d.id.idx = r->d.id.idx;
5725 res.t = BC_RESULT_STR;
5728 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5730 bc_vec_pop(&G.prog.results);
5733 bc_vec_pop(&G.prog.results);
5735 bc_vec_push(&G.prog.results, &res);
5736 bc_vec_push(v, &n2);
5738 return BC_STATUS_SUCCESS;
5742 static BcStatus bc_program_copyToVar(char *name, bool var)
5749 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5751 ptr = bc_vec_top(&G.prog.results);
5752 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5753 v = bc_program_search(name, var);
5756 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5757 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5760 s = bc_program_num(ptr, &n, false);
5763 // Do this once more to make sure that pointers were not invalidated.
5764 v = bc_program_search(name, var);
5767 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5768 bc_num_copy(&r.d.n, n);
5771 bc_array_init(&r.d.v, true);
5772 bc_array_copy(&r.d.v, (BcVec *) n);
5775 bc_vec_push(v, &r.d);
5776 bc_vec_pop(&G.prog.results);
5781 static BcStatus bc_program_assign(char inst)
5784 BcResult *left, *right, res;
5785 BcNum *l = NULL, *r = NULL;
5786 unsigned long val, max;
5787 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5789 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5792 ib = left->t == BC_RESULT_IBASE;
5793 sc = left->t == BC_RESULT_SCALE;
5797 if (right->t == BC_RESULT_STR) {
5801 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5802 v = bc_program_search(left->d.id.name, true);
5804 return bc_program_assignStr(right, v, false);
5808 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5809 return BC_STATUS_PARSE_BAD_ASSIGN;
5812 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5813 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5818 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5825 if (ib || sc || left->t == BC_RESULT_OBASE) {
5829 s = bc_num_ulong(l, &val);
5831 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5835 ptr = &G.prog.scale;
5838 if (val < BC_NUM_MIN_BASE) return s;
5839 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5840 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5843 if (val > max) return s;
5844 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5846 *ptr = (size_t) val;
5847 s = BC_STATUS_SUCCESS;
5850 bc_num_init(&res.d.n, l->len);
5851 bc_num_copy(&res.d.n, l);
5852 bc_program_binOpRetire(&res);
5858 #define bc_program_pushVar(code, bgn, pop, copy) \
5859 bc_program_pushVar(code, bgn)
5860 // for bc, 'pop' and 'copy' are always false
5862 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5863 bool pop, bool copy)
5865 BcStatus s = BC_STATUS_SUCCESS;
5867 char *name = bc_program_name(code, bgn);
5869 r.t = BC_RESULT_VAR;
5874 BcVec *v = bc_program_search(name, true);
5875 BcNum *num = bc_vec_top(v);
5879 if (!BC_PROG_STACK(v, 2 - copy)) {
5881 return BC_STATUS_EXEC_STACK;
5887 if (!BC_PROG_STR(num)) {
5889 r.t = BC_RESULT_TEMP;
5891 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5892 bc_num_copy(&r.d.n, num);
5895 r.t = BC_RESULT_STR;
5896 r.d.id.idx = num->rdx;
5899 if (!copy) bc_vec_pop(v);
5904 bc_vec_push(&G.prog.results, &r);
5909 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5912 BcStatus s = BC_STATUS_SUCCESS;
5916 r.d.id.name = bc_program_name(code, bgn);
5918 if (inst == BC_INST_ARRAY) {
5919 r.t = BC_RESULT_ARRAY;
5920 bc_vec_push(&G.prog.results, &r);
5927 s = bc_program_prep(&operand, &num);
5929 s = bc_num_ulong(num, &temp);
5932 if (temp > BC_MAX_DIM) {
5933 s = BC_STATUS_EXEC_ARRAY_LEN;
5937 r.d.id.idx = (size_t) temp;
5938 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5942 if (s) free(r.d.id.name);
5947 static BcStatus bc_program_incdec(char inst)
5950 BcResult *ptr, res, copy;
5954 s = bc_program_prep(&ptr, &num);
5957 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5958 copy.t = BC_RESULT_TEMP;
5959 bc_num_init(©.d.n, num->len);
5960 bc_num_copy(©.d.n, num);
5963 res.t = BC_RESULT_ONE;
5964 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5965 BC_INST_ASSIGN_PLUS :
5966 BC_INST_ASSIGN_MINUS;
5968 bc_vec_push(&G.prog.results, &res);
5969 bc_program_assign(inst);
5971 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5972 bc_vec_pop(&G.prog.results);
5973 bc_vec_push(&G.prog.results, ©);
5979 static BcStatus bc_program_call(char *code, size_t *idx)
5981 BcStatus s = BC_STATUS_SUCCESS;
5983 size_t i, nparams = bc_program_index(code, idx);
5990 ip.func = bc_program_index(code, idx);
5991 func = bc_vec_item(&G.prog.fns, ip.func);
5993 if (func->code.len == 0) {
5994 return bc_error("undefined function");
5996 if (nparams != func->nparams) {
5997 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5999 ip.len = G.prog.results.len - nparams;
6001 for (i = 0; i < nparams; ++i) {
6003 a = bc_vec_item(&func->autos, nparams - 1 - i);
6004 arg = bc_vec_top(&G.prog.results);
6006 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6007 return BC_STATUS_EXEC_BAD_TYPE;
6009 s = bc_program_copyToVar(a->name, a->idx);
6013 for (; i < func->autos.len; ++i) {
6016 a = bc_vec_item(&func->autos, i);
6017 v = bc_program_search(a->name, a->idx);
6020 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6021 bc_vec_push(v, ¶m.n);
6024 bc_array_init(¶m.v, true);
6025 bc_vec_push(v, ¶m.v);
6029 bc_vec_push(&G.prog.stack, &ip);
6031 return BC_STATUS_SUCCESS;
6034 static BcStatus bc_program_return(char inst)
6040 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6042 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6043 return BC_STATUS_EXEC_STACK;
6045 f = bc_vec_item(&G.prog.fns, ip->func);
6046 res.t = BC_RESULT_TEMP;
6048 if (inst == BC_INST_RET) {
6051 BcResult *operand = bc_vec_top(&G.prog.results);
6053 s = bc_program_num(operand, &num, false);
6055 bc_num_init(&res.d.n, num->len);
6056 bc_num_copy(&res.d.n, num);
6059 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6060 bc_num_zero(&res.d.n);
6063 // We need to pop arguments as well, so this takes that into account.
6064 for (i = 0; i < f->autos.len; ++i) {
6067 BcId *a = bc_vec_item(&f->autos, i);
6069 v = bc_program_search(a->name, a->idx);
6073 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6074 bc_vec_push(&G.prog.results, &res);
6075 bc_vec_pop(&G.prog.stack);
6077 return BC_STATUS_SUCCESS;
6081 static unsigned long bc_program_scale(BcNum *n)
6083 return (unsigned long) n->rdx;
6086 static unsigned long bc_program_len(BcNum *n)
6088 unsigned long len = n->len;
6091 if (n->rdx != n->len) return len;
6092 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6097 static BcStatus bc_program_builtin(char inst)
6103 bool len = inst == BC_INST_LENGTH;
6105 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6106 opnd = bc_vec_top(&G.prog.results);
6108 s = bc_program_num(opnd, &num, false);
6112 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6115 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6117 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6119 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6120 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6124 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6127 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6129 str = bc_vec_item(&G.prog.strs, idx);
6130 bc_num_ulong2num(&res.d.n, strlen(*str));
6134 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6135 bc_num_ulong2num(&res.d.n, f(num));
6138 bc_program_retire(&res, BC_RESULT_TEMP);
6144 static BcStatus bc_program_divmod(void)
6147 BcResult *opd1, *opd2, res, res2;
6148 BcNum *n1, *n2 = NULL;
6150 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6153 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6154 bc_num_init(&res2.d.n, n2->len);
6156 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6159 bc_program_binOpRetire(&res2);
6160 res.t = BC_RESULT_TEMP;
6161 bc_vec_push(&G.prog.results, &res);
6166 bc_num_free(&res2.d.n);
6167 bc_num_free(&res.d.n);
6171 static BcStatus bc_program_modexp(void)
6174 BcResult *r1, *r2, *r3, res;
6175 BcNum *n1, *n2, *n3;
6177 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6178 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6181 r1 = bc_vec_item_rev(&G.prog.results, 2);
6182 s = bc_program_num(r1, &n1, false);
6184 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6186 // Make sure that the values have their pointers updated, if necessary.
6187 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6189 if (r1->t == r2->t) {
6190 s = bc_program_num(r2, &n2, false);
6194 if (r1->t == r3->t) {
6195 s = bc_program_num(r3, &n3, false);
6200 bc_num_init(&res.d.n, n3->len);
6201 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6204 bc_vec_pop(&G.prog.results);
6205 bc_program_binOpRetire(&res);
6210 bc_num_free(&res.d.n);
6214 static void bc_program_stackLen(void)
6217 size_t len = G.prog.results.len;
6219 res.t = BC_RESULT_TEMP;
6221 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6222 bc_num_ulong2num(&res.d.n, len);
6223 bc_vec_push(&G.prog.results, &res);
6226 static BcStatus bc_program_asciify(void)
6230 BcNum *num = NULL, n;
6231 char *str, *str2, c;
6232 size_t len = G.prog.strs.len, idx;
6235 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6236 r = bc_vec_top(&G.prog.results);
6238 s = bc_program_num(r, &num, false);
6241 if (BC_PROG_NUM(r, num)) {
6243 bc_num_init(&n, BC_NUM_DEF_SIZE);
6244 bc_num_copy(&n, num);
6245 bc_num_truncate(&n, n.rdx);
6247 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6248 if (s) goto num_err;
6249 s = bc_num_ulong(&n, &val);
6250 if (s) goto num_err;
6257 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6258 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6266 str2 = xstrdup(str);
6267 bc_program_addFunc(str2, &idx);
6269 if (idx != len + BC_PROG_REQ_FUNCS) {
6271 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6272 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6281 bc_vec_push(&G.prog.strs, &str);
6283 res.t = BC_RESULT_STR;
6285 bc_vec_pop(&G.prog.results);
6286 bc_vec_push(&G.prog.results, &res);
6288 return BC_STATUS_SUCCESS;
6295 static BcStatus bc_program_printStream(void)
6303 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6304 r = bc_vec_top(&G.prog.results);
6306 s = bc_program_num(r, &n, false);
6309 if (BC_PROG_NUM(r, n))
6310 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6312 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6313 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6320 static BcStatus bc_program_nquit(void)
6327 s = bc_program_prep(&opnd, &num);
6329 s = bc_num_ulong(num, &val);
6332 bc_vec_pop(&G.prog.results);
6334 if (G.prog.stack.len < val)
6335 return BC_STATUS_EXEC_STACK;
6336 if (G.prog.stack.len == val)
6339 bc_vec_npop(&G.prog.stack, val);
6344 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6347 BcStatus s = BC_STATUS_SUCCESS;
6357 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6359 r = bc_vec_top(&G.prog.results);
6363 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6365 if (code[*bgn] == BC_PARSE_STREND)
6368 else_name = bc_program_name(code, bgn);
6370 exec = r->d.n.len != 0;
6374 else if (else_name != NULL) {
6381 v = bc_program_search(name, true);
6388 if (!exec) goto exit;
6389 if (!BC_PROG_STR(n)) {
6390 s = BC_STATUS_EXEC_BAD_TYPE;
6398 if (r->t == BC_RESULT_STR)
6400 else if (r->t == BC_RESULT_VAR) {
6401 s = bc_program_num(r, &n, false);
6402 if (s || !BC_PROG_STR(n)) goto exit;
6409 fidx = sidx + BC_PROG_REQ_FUNCS;
6411 str = bc_vec_item(&G.prog.strs, sidx);
6412 f = bc_vec_item(&G.prog.fns, fidx);
6414 if (f->code.len == 0) {
6415 common_parse_init(&prs, fidx);
6416 s = bc_parse_text(&prs, *str);
6418 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6421 if (prs.l.t.t != BC_LEX_EOF) {
6422 s = BC_STATUS_PARSE_BAD_EXP;
6426 bc_parse_free(&prs);
6430 ip.len = G.prog.results.len;
6433 bc_vec_pop(&G.prog.results);
6434 bc_vec_push(&G.prog.stack, &ip);
6436 return BC_STATUS_SUCCESS;
6439 bc_parse_free(&prs);
6440 f = bc_vec_item(&G.prog.fns, fidx);
6441 bc_vec_npop(&f->code, f->code.len);
6443 bc_vec_pop(&G.prog.results);
6448 static void bc_program_pushGlobal(char inst)
6453 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6454 if (inst == BC_INST_IBASE)
6455 val = (unsigned long) G.prog.ib_t;
6456 else if (inst == BC_INST_SCALE)
6457 val = (unsigned long) G.prog.scale;
6459 val = (unsigned long) G.prog.ob_t;
6461 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6462 bc_num_ulong2num(&res.d.n, val);
6463 bc_vec_push(&G.prog.results, &res);
6466 static void bc_program_addFunc(char *name, size_t *idx)
6468 BcId entry, *entry_ptr;
6473 entry.idx = G.prog.fns.len;
6475 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6476 if (!inserted) free(name);
6478 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6479 *idx = entry_ptr->idx;
6483 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6485 // We need to reset these, so the function can be repopulated.
6487 bc_vec_npop(&func->autos, func->autos.len);
6488 bc_vec_npop(&func->code, func->code.len);
6489 bc_vec_npop(&func->labels, func->labels.len);
6493 bc_vec_push(&G.prog.fns, &f);
6497 static BcStatus bc_program_reset(BcStatus s)
6502 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6503 bc_vec_npop(&G.prog.results, G.prog.results.len);
6505 f = bc_vec_item(&G.prog.fns, 0);
6506 ip = bc_vec_top(&G.prog.stack);
6507 ip->idx = f->code.len;
6509 if (!s && G_interrupt && !G.tty) quit();
6511 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6514 fflush_and_check(); // make sure buffered stdout is printed
6515 fputs(bc_program_ready_msg, stderr);
6517 s = BC_STATUS_SUCCESS;
6523 static BcStatus bc_program_exec(void)
6525 BcStatus s = BC_STATUS_SUCCESS;
6529 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6530 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6531 char *code = func->code.v;
6534 while (!s && ip->idx < func->code.len) {
6536 char inst = code[(ip->idx)++];
6541 case BC_INST_JUMP_ZERO:
6543 s = bc_program_prep(&ptr, &num);
6545 cond = !bc_num_cmp(num, &G.prog.zero);
6546 bc_vec_pop(&G.prog.results);
6552 idx = bc_program_index(code, &ip->idx);
6553 addr = bc_vec_item(&func->labels, idx);
6554 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6560 s = bc_program_call(code, &ip->idx);
6564 case BC_INST_INC_PRE:
6565 case BC_INST_DEC_PRE:
6566 case BC_INST_INC_POST:
6567 case BC_INST_DEC_POST:
6569 s = bc_program_incdec(inst);
6582 s = bc_program_return(inst);
6586 case BC_INST_BOOL_OR:
6587 case BC_INST_BOOL_AND:
6589 case BC_INST_REL_EQ:
6590 case BC_INST_REL_LE:
6591 case BC_INST_REL_GE:
6592 case BC_INST_REL_NE:
6593 case BC_INST_REL_LT:
6594 case BC_INST_REL_GT:
6596 s = bc_program_logical(inst);
6602 s = bc_program_read();
6608 s = bc_program_pushVar(code, &ip->idx, false, false);
6612 case BC_INST_ARRAY_ELEM:
6615 s = bc_program_pushArray(code, &ip->idx, inst);
6621 r.t = BC_RESULT_LAST;
6622 bc_vec_push(&G.prog.results, &r);
6630 bc_program_pushGlobal(inst);
6634 case BC_INST_SCALE_FUNC:
6635 case BC_INST_LENGTH:
6638 s = bc_program_builtin(inst);
6644 r.t = BC_RESULT_CONSTANT;
6645 r.d.id.idx = bc_program_index(code, &ip->idx);
6646 bc_vec_push(&G.prog.results, &r);
6652 if (!BC_PROG_STACK(&G.prog.results, 1))
6653 s = BC_STATUS_EXEC_STACK;
6655 bc_vec_pop(&G.prog.results);
6659 case BC_INST_POP_EXEC:
6661 bc_vec_pop(&G.prog.stack);
6666 case BC_INST_PRINT_POP:
6667 case BC_INST_PRINT_STR:
6669 s = bc_program_print(inst, 0);
6675 r.t = BC_RESULT_STR;
6676 r.d.id.idx = bc_program_index(code, &ip->idx);
6677 bc_vec_push(&G.prog.results, &r);
6682 case BC_INST_MULTIPLY:
6683 case BC_INST_DIVIDE:
6684 case BC_INST_MODULUS:
6688 s = bc_program_op(inst);
6692 case BC_INST_BOOL_NOT:
6694 s = bc_program_prep(&ptr, &num);
6697 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6698 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6699 bc_program_retire(&r, BC_RESULT_TEMP);
6706 s = bc_program_negate();
6711 case BC_INST_ASSIGN_POWER:
6712 case BC_INST_ASSIGN_MULTIPLY:
6713 case BC_INST_ASSIGN_DIVIDE:
6714 case BC_INST_ASSIGN_MODULUS:
6715 case BC_INST_ASSIGN_PLUS:
6716 case BC_INST_ASSIGN_MINUS:
6718 case BC_INST_ASSIGN:
6720 s = bc_program_assign(inst);
6724 case BC_INST_MODEXP:
6726 s = bc_program_modexp();
6730 case BC_INST_DIVMOD:
6732 s = bc_program_divmod();
6736 case BC_INST_EXECUTE:
6737 case BC_INST_EXEC_COND:
6739 cond = inst == BC_INST_EXEC_COND;
6740 s = bc_program_execStr(code, &ip->idx, cond);
6744 case BC_INST_PRINT_STACK:
6746 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6747 s = bc_program_print(BC_INST_PRINT, idx);
6751 case BC_INST_CLEAR_STACK:
6753 bc_vec_npop(&G.prog.results, G.prog.results.len);
6757 case BC_INST_STACK_LEN:
6759 bc_program_stackLen();
6763 case BC_INST_DUPLICATE:
6765 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6766 ptr = bc_vec_top(&G.prog.results);
6767 bc_result_copy(&r, ptr);
6768 bc_vec_push(&G.prog.results, &r);
6776 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6778 ptr = bc_vec_item_rev(&G.prog.results, 0);
6779 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6780 memcpy(&r, ptr, sizeof(BcResult));
6781 memcpy(ptr, ptr2, sizeof(BcResult));
6782 memcpy(ptr2, &r, sizeof(BcResult));
6787 case BC_INST_ASCIIFY:
6789 s = bc_program_asciify();
6793 case BC_INST_PRINT_STREAM:
6795 s = bc_program_printStream();
6800 case BC_INST_PUSH_VAR:
6802 bool copy = inst == BC_INST_LOAD;
6803 s = bc_program_pushVar(code, &ip->idx, true, copy);
6807 case BC_INST_PUSH_TO_VAR:
6809 char *name = bc_program_name(code, &ip->idx);
6810 s = bc_program_copyToVar(name, true);
6817 if (G.prog.stack.len <= 2)
6819 bc_vec_npop(&G.prog.stack, 2);
6825 s = bc_program_nquit();
6831 if (s || G_interrupt) s = bc_program_reset(s);
6833 // If the stack has changed, pointers may be invalid.
6834 ip = bc_vec_top(&G.prog.stack);
6835 func = bc_vec_item(&G.prog.fns, ip->func);
6836 code = func->code.v;
6842 static void bc_vm_info(void)
6844 printf("%s "BB_VER"\n"
6845 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6846 "Report bugs at: https://github.com/gavinhoward/bc\n"
6847 "This is free software with ABSOLUTELY NO WARRANTY\n"
6851 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6853 if (!s || s > BC_STATUS_BEFORE_POSIX) return s;
6855 if (bc_err_msgs[s]) {
6856 fprintf(stderr, bc_err_fmt, bc_err_msgs[s]);
6857 fprintf(stderr, " %s", file);
6858 fprintf(stderr, bc_err_line + 4 * !line, line);
6861 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6865 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6870 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W))) return BC_STATUS_SUCCESS;
6871 if (s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6873 fmt = G_posix ? bc_err_fmt : bc_warn_fmt;
6874 fprintf(stderr, fmt, bc_err_msgs[s]);
6875 if (msg) fprintf(stderr, " %s\n", msg);
6876 fprintf(stderr, " %s", file);
6877 fprintf(stderr, bc_err_line + 4 * !line, line);
6879 if (G.ttyin || !G_posix)
6880 s = BC_STATUS_SUCCESS;
6884 static void bc_vm_envArgs(void)
6886 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6889 char *env_args = getenv(bc_args_env_name), *buf;
6891 if (!env_args) return;
6893 G.env_args = xstrdup(env_args);
6896 bc_vec_init(&v, sizeof(char *), NULL);
6897 bc_vec_push(&v, &bc_args_env_name);
6900 if (!isspace(*buf)) {
6901 bc_vec_push(&v, &buf);
6902 while (*buf != 0 && !isspace(*buf)) ++buf;
6903 if (*buf != 0) (*(buf++)) = '\0';
6909 bc_args((int) v.len, (char **) v.v);
6915 static size_t bc_vm_envLen(const char *var)
6917 char *lenv = getenv(var);
6918 size_t i, len = BC_NUM_PRINT_WIDTH;
6921 if (!lenv) return len;
6925 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6927 len = (size_t) atoi(lenv) - 1;
6928 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6931 len = BC_NUM_PRINT_WIDTH;
6936 static BcStatus bc_vm_process(const char *text)
6938 BcStatus s = bc_parse_text(&G.prs, text);
6940 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6943 while (G.prs.l.t.t != BC_LEX_EOF) {
6945 s = G.prs.parse(&G.prs);
6947 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6951 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6952 s = bc_program_exec();
6955 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
6961 static BcStatus bc_vm_file(const char *file)
6969 data = bc_read_file(file);
6970 if (!data) return bc_error("file '%s' is not text", file);
6972 bc_lex_file(&G.prs.l, file);
6973 s = bc_vm_process(data);
6976 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6977 ip = bc_vec_item(&G.prog.stack, 0);
6979 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
6986 static BcStatus bc_vm_stdin(void)
6990 size_t len, i, str = 0;
6991 bool comment = false;
6993 G.prog.file = bc_program_stdin_name;
6994 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6996 bc_vec_init(&buffer, sizeof(char), NULL);
6997 bc_vec_init(&buf, sizeof(char), NULL);
6998 bc_vec_pushByte(&buffer, '\0');
7000 // This loop is complex because the vm tries not to send any lines that end
7001 // with a backslash to the parser. The reason for that is because the parser
7002 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7003 // case, and for strings and comments, the parser will expect more stuff.
7004 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7006 char *string = buf.v;
7011 if (str && buf.v[0] == G.send)
7013 else if (buf.v[0] == G.sbgn)
7016 else if (len > 1 || comment) {
7018 for (i = 0; i < len; ++i) {
7020 bool notend = len > i + 1;
7023 if (i - 1 > len || string[i - 1] != '\\') {
7024 if (G.sbgn == G.send)
7026 else if (c == G.send)
7028 else if (c == G.sbgn)
7032 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7036 else if (c == '*' && notend && comment && string[i + 1] == '/')
7040 if (str || comment || string[len - 2] == '\\') {
7041 bc_vec_concat(&buffer, buf.v);
7046 bc_vec_concat(&buffer, buf.v);
7047 s = bc_vm_process(buffer.v);
7050 bc_vec_npop(&buffer, buffer.len);
7054 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7057 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7062 bc_vec_free(&buffer);
7066 static BcStatus bc_vm_exec(void)
7068 BcStatus s = BC_STATUS_SUCCESS;
7072 if (G.flags & BC_FLAG_L) {
7074 bc_lex_file(&G.prs.l, bc_lib_name);
7075 s = bc_parse_text(&G.prs, bc_lib);
7077 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7080 s = bc_program_exec();
7085 for (i = 0; !s && i < G.files.len; ++i)
7086 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7089 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7090 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7095 #if ENABLE_FEATURE_CLEAN_UP
7096 static void bc_program_free()
7098 bc_num_free(&G.prog.ib);
7099 bc_num_free(&G.prog.ob);
7100 bc_num_free(&G.prog.hexb);
7102 bc_num_free(&G.prog.strmb);
7104 bc_vec_free(&G.prog.fns);
7105 bc_vec_free(&G.prog.fn_map);
7106 bc_vec_free(&G.prog.vars);
7107 bc_vec_free(&G.prog.var_map);
7108 bc_vec_free(&G.prog.arrs);
7109 bc_vec_free(&G.prog.arr_map);
7110 bc_vec_free(&G.prog.strs);
7111 bc_vec_free(&G.prog.consts);
7112 bc_vec_free(&G.prog.results);
7113 bc_vec_free(&G.prog.stack);
7114 bc_num_free(&G.prog.last);
7115 bc_num_free(&G.prog.zero);
7116 bc_num_free(&G.prog.one);
7119 static void bc_vm_free(void)
7121 bc_vec_free(&G.files);
7123 bc_parse_free(&G.prs);
7128 static void bc_program_init(size_t line_len)
7133 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7134 memset(&ip, 0, sizeof(BcInstPtr));
7136 /* G.prog.nchars = G.prog.scale = 0; - already is */
7137 G.prog.len = line_len;
7139 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7140 bc_num_ten(&G.prog.ib);
7143 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7144 bc_num_ten(&G.prog.ob);
7147 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7148 bc_num_ten(&G.prog.hexb);
7149 G.prog.hexb.num[0] = 6;
7152 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7153 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7156 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7157 bc_num_zero(&G.prog.last);
7159 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7160 bc_num_zero(&G.prog.zero);
7162 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7163 bc_num_one(&G.prog.one);
7165 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7166 bc_map_init(&G.prog.fn_map);
7168 bc_program_addFunc(xstrdup("(main)"), &idx);
7169 bc_program_addFunc(xstrdup("(read)"), &idx);
7171 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7172 bc_map_init(&G.prog.var_map);
7174 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7175 bc_map_init(&G.prog.arr_map);
7177 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7178 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7179 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7180 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7181 bc_vec_push(&G.prog.stack, &ip);
7184 static void bc_vm_init(const char *env_len)
7186 size_t len = bc_vm_envLen(env_len);
7188 #if ENABLE_FEATURE_BC_SIGNALS
7189 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7192 bc_vec_init(&G.files, sizeof(char *), NULL);
7195 if (getenv("POSIXLY_CORRECT"))
7196 G.flags |= BC_FLAG_S;
7200 bc_program_init(len);
7202 bc_parse_init(&G.prs, BC_PROG_MAIN);
7204 dc_parse_init(&G.prs, BC_PROG_MAIN);
7208 static BcStatus bc_vm_run(int argc, char *argv[],
7209 const char *env_len)
7213 bc_vm_init(env_len);
7214 bc_args(argc, argv);
7216 G.ttyin = isatty(0);
7217 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7219 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7222 #if ENABLE_FEATURE_CLEAN_UP
7229 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7230 int bc_main(int argc, char **argv)
7233 G.sbgn = G.send = '"';
7235 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7240 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7241 int dc_main(int argc, char **argv)
7247 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");