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,
222 BC_STATUS_POSIX_NAME_LEN,
223 BC_STATUS_POSIX_COMMENT,
224 BC_STATUS_POSIX_BAD_KW,
227 BC_STATUS_POSIX_BOOL,
228 BC_STATUS_POSIX_REL_POS,
229 BC_STATUS_POSIX_MULTIREL,
230 BC_STATUS_POSIX_FOR1,
231 BC_STATUS_POSIX_FOR2,
232 BC_STATUS_POSIX_FOR3,
233 BC_STATUS_POSIX_BRACE,
238 // BC_STATUS_INVALID_OPTION,
240 // Keep enum above and messages below in sync!
241 static const char *const bc_err_msgs[] = {
244 // "memory allocation error",
246 // "file is not text:",
247 // "path is a directory:",
250 "string end could not be found",
251 "comment end could not be found",
259 "bad print statement",
260 "bad function definition",
261 "bad assignment: left side must be scale, ibase, "
262 "obase, last, var, or array element",
263 "no auto variable found",
264 "function parameter or auto var has the same name as another",
265 "block end could not be found",
268 "non integer number",
273 // "could not open file:",
274 "mismatched parameters", // wrong number of them, to be exact
275 "undefined function",
276 "file is not executable:",
277 "number too long: must be [1, BC_NUM_MAX]",
278 "name too long: must be [1, BC_NAME_MAX]",
279 "string too long: must be [1, BC_STRING_MAX]",
280 "array too long; must be [1, BC_DIM_MAX]",
281 "bad ibase; must be [2, 16]",
282 // "bad scale; must be [0, BC_SCALE_MAX]",
283 "bad read() expression",
284 "read() call inside of a read() call",
285 "variable is wrong type",
286 // "bad obase; must be [2, BC_BASE_MAX]",
287 "signal caught and not handled",
288 "stack has too few elements",
290 // "index is out of bounds",
291 "item already exists",
293 "POSIX only allows one character names; the following is bad:",
294 "POSIX does not allow '#' script comments",
295 "POSIX does not allow the following keyword:",
296 "POSIX does not allow a period ('.') as a shortcut for the last result",
297 "POSIX requires parentheses around return expressions",
298 "POSIX does not allow boolean operators; the following is bad:",
299 "POSIX does not allow comparison operators outside if or loops",
300 "POSIX requires exactly one comparison operator per condition",
301 "POSIX does not allow an empty init expression in a for loop",
302 "POSIX does not allow an empty condition expression in a for loop",
303 "POSIX does not allow an empty update expression in a for loop",
304 "POSIX requires the left brace be on the same line as the function header",
308 #define BC_VEC_INVALID_IDX ((size_t) -1)
309 #define BC_VEC_START_CAP (1 << 5)
311 typedef void (*BcVecFree)(void *);
313 typedef struct BcVec {
321 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
322 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
324 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
326 typedef signed char BcDig;
328 typedef struct BcNum {
336 #define BC_NUM_MIN_BASE ((unsigned long) 2)
337 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
338 #define BC_NUM_DEF_SIZE (16)
339 #define BC_NUM_PRINT_WIDTH (69)
341 #define BC_NUM_KARATSUBA_LEN (32)
343 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
344 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
345 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
346 #define BC_NUM_AREQ(a, b) \
347 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
348 #define BC_NUM_MREQ(a, b, scale) \
349 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
351 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
352 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
354 static void bc_num_init(BcNum *n, size_t req);
355 static void bc_num_expand(BcNum *n, size_t req);
356 static void bc_num_copy(BcNum *d, BcNum *s);
357 static void bc_num_free(void *num);
359 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
360 static void bc_num_ulong2num(BcNum *n, unsigned long val);
362 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
363 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
364 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
365 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
366 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
367 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
368 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
369 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
372 typedef enum BcInst {
402 BC_INST_ASSIGN_POWER,
403 BC_INST_ASSIGN_MULTIPLY,
404 BC_INST_ASSIGN_DIVIDE,
405 BC_INST_ASSIGN_MODULUS,
407 BC_INST_ASSIGN_MINUS,
453 BC_INST_PRINT_STREAM,
468 BC_INST_INVALID = -1,
473 typedef struct BcId {
478 typedef struct BcFunc {
485 typedef enum BcResultType {
490 BC_RESULT_ARRAY_ELEM,
499 // These are between to calculate ibase, obase, and last from instructions.
507 typedef union BcResultData {
513 typedef struct BcResult {
518 typedef struct BcInstPtr {
524 static void bc_array_expand(BcVec *a, size_t len);
525 static int bc_id_cmp(const void *e1, const void *e2);
527 // BC_LEX_NEG is not used in lexing; it is only for parsing.
528 typedef enum BcLexType {
556 BC_LEX_OP_ASSIGN_POWER,
557 BC_LEX_OP_ASSIGN_MULTIPLY,
558 BC_LEX_OP_ASSIGN_DIVIDE,
559 BC_LEX_OP_ASSIGN_MODULUS,
560 BC_LEX_OP_ASSIGN_PLUS,
561 BC_LEX_OP_ASSIGN_MINUS,
635 typedef BcStatus (*BcLexNext)(struct BcLex *);
637 typedef struct BcLex {
656 #define BC_PARSE_STREND ((char) UCHAR_MAX)
658 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
659 #define bc_parse_updateFunc(p, f) \
660 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
662 #define BC_PARSE_REL (1 << 0)
663 #define BC_PARSE_PRINT (1 << 1)
664 #define BC_PARSE_NOCALL (1 << 2)
665 #define BC_PARSE_NOREAD (1 << 3)
666 #define BC_PARSE_ARRAY (1 << 4)
668 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
669 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
671 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
672 #define BC_PARSE_FUNC_INNER(parse) \
673 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
675 #define BC_PARSE_FLAG_FUNC (1 << 1)
676 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
678 #define BC_PARSE_FLAG_BODY (1 << 2)
679 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
681 #define BC_PARSE_FLAG_LOOP (1 << 3)
682 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
684 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
685 #define BC_PARSE_LOOP_INNER(parse) \
686 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
688 #define BC_PARSE_FLAG_IF (1 << 5)
689 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
691 #define BC_PARSE_FLAG_ELSE (1 << 6)
692 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
694 #define BC_PARSE_FLAG_IF_END (1 << 7)
695 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
697 #define BC_PARSE_CAN_EXEC(parse) \
698 (!(BC_PARSE_TOP_FLAG(parse) & \
699 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
700 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
701 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
703 typedef struct BcOp {
708 typedef struct BcParseNext {
713 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
714 #define BC_PARSE_NEXT(a, ...) \
716 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
723 typedef BcStatus (*BcParseParse)(struct BcParse *);
725 typedef struct BcParse {
748 typedef struct BcLexKeyword {
754 #define BC_LEX_KW_ENTRY(a, b, c) \
756 .name = a, .len = (b), .posix = (c) \
759 static BcStatus bc_lex_token(BcLex *l);
761 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
762 #define BC_PARSE_LEAF(p, rparen) \
763 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
764 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
766 // We can calculate the conversion between tokens and exprs by subtracting the
767 // position of the first operator in the lex enum and adding the position of the
768 // first in the expr enum. Note: This only works for binary operators.
769 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
771 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
777 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
779 static BcStatus dc_lex_token(BcLex *l);
781 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
785 typedef struct BcProgram {
826 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
828 #define BC_PROG_MAIN (0)
829 #define BC_PROG_READ (1)
832 #define BC_PROG_REQ_FUNCS (2)
835 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
836 #define BC_PROG_NUM(r, n) \
837 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
839 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
841 static void bc_program_addFunc(char *name, size_t *idx);
842 static BcStatus bc_program_reset(BcStatus s);
844 #define BC_FLAG_X (1 << 0)
845 #define BC_FLAG_W (1 << 1)
846 #define BC_FLAG_V (1 << 2)
847 #define BC_FLAG_S (1 << 3)
848 #define BC_FLAG_Q (1 << 4)
849 #define BC_FLAG_L (1 << 5)
850 #define BC_FLAG_I (1 << 6)
852 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
853 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
855 #define BC_MAX_OBASE ((unsigned) 999)
856 #define BC_MAX_DIM ((unsigned) INT_MAX)
857 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
858 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
859 #define BC_MAX_NAME BC_MAX_STRING
860 #define BC_MAX_NUM BC_MAX_STRING
861 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
862 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
880 #define G (*ptr_to_globals)
881 #define INIT_G() do { \
882 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
884 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
885 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
886 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
887 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
890 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
893 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
897 static void bc_vm_info(void);
899 static const char bc_err_fmt[] = "\nerror: %s\n";
900 static const char bc_warn_fmt[] = "\nwarning: %s\n";
901 static const char bc_err_line[] = ":%zu\n\n";
904 static const BcLexKeyword bc_lex_kws[20] = {
905 BC_LEX_KW_ENTRY("auto", 4, true),
906 BC_LEX_KW_ENTRY("break", 5, true),
907 BC_LEX_KW_ENTRY("continue", 8, false),
908 BC_LEX_KW_ENTRY("define", 6, true),
909 BC_LEX_KW_ENTRY("else", 4, false),
910 BC_LEX_KW_ENTRY("for", 3, true),
911 BC_LEX_KW_ENTRY("halt", 4, false),
912 BC_LEX_KW_ENTRY("ibase", 5, true),
913 BC_LEX_KW_ENTRY("if", 2, true),
914 BC_LEX_KW_ENTRY("last", 4, false),
915 BC_LEX_KW_ENTRY("length", 6, true),
916 BC_LEX_KW_ENTRY("limits", 6, false),
917 BC_LEX_KW_ENTRY("obase", 5, true),
918 BC_LEX_KW_ENTRY("print", 5, false),
919 BC_LEX_KW_ENTRY("quit", 4, true),
920 BC_LEX_KW_ENTRY("read", 4, false),
921 BC_LEX_KW_ENTRY("return", 6, true),
922 BC_LEX_KW_ENTRY("scale", 5, true),
923 BC_LEX_KW_ENTRY("sqrt", 4, true),
924 BC_LEX_KW_ENTRY("while", 5, true),
927 // This is an array that corresponds to token types. An entry is
928 // true if the token is valid in an expression, false otherwise.
929 static const bool bc_parse_exprs[] = {
930 false, false, true, true, true, true, true, true, true, true, true, true,
931 true, true, true, true, true, true, true, true, true, true, true, true,
932 true, true, true, false, false, true, true, false, false, false, false,
933 false, false, false, true, true, false, false, false, false, false, false,
934 false, true, false, true, true, true, true, false, false, true, false, true,
938 // This is an array of data for operators that correspond to token types.
939 static const BcOp bc_parse_ops[] = {
940 { 0, false }, { 0, false },
943 { 3, true }, { 3, true }, { 3, true },
944 { 4, true }, { 4, true },
945 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
947 { 7, true }, { 7, true },
948 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
949 { 5, false }, { 5, false },
952 // These identify what tokens can come after expressions in certain cases.
953 static const BcParseNext bc_parse_next_expr =
954 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
955 static const BcParseNext bc_parse_next_param =
956 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
957 static const BcParseNext bc_parse_next_print =
958 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
959 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
960 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
961 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
962 static const BcParseNext bc_parse_next_read =
963 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
967 static const BcLexType dc_lex_regs[] = {
968 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
969 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
970 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
974 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
976 static const BcLexType dc_lex_tokens[] = {
977 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
978 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
979 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
980 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
981 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
982 BC_LEX_INVALID, BC_LEX_INVALID,
983 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
984 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
985 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
986 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
987 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
988 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
989 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
990 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
991 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
992 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
993 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
994 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
995 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
996 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
997 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
998 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
999 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1000 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1004 static const BcInst dc_parse_insts[] = {
1005 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1006 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1007 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1008 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1009 BC_INST_INVALID, BC_INST_INVALID,
1010 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1011 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1012 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1013 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1014 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1015 BC_INST_INVALID, BC_INST_INVALID,
1016 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1017 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1018 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1019 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1020 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1021 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1022 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1023 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1024 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1025 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1026 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1027 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1031 static const BcNumBinaryOp bc_program_ops[] = {
1032 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1035 static const char bc_program_stdin_name[] = "<stdin>";
1036 static const char bc_program_ready_msg[] = "ready for more input\n";
1039 static const char *bc_lib_name = "gen/lib.bc";
1041 static const char bc_lib[] = {
1042 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1043 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1044 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1045 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,
1046 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1047 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1048 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,
1049 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1050 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1051 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,
1052 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1053 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1054 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1055 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1056 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1057 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1058 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1059 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1060 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1061 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1062 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1063 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1064 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1065 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,
1066 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1067 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,
1068 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1069 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1070 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1071 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1072 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1073 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,
1074 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1075 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1076 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1077 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1078 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,
1079 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1080 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1081 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1082 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1083 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1084 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1085 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1086 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1087 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1088 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1089 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,
1090 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,
1091 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1092 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,
1093 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,
1094 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,
1095 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1096 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1097 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,
1098 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,
1099 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,
1100 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1101 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,
1102 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1103 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1104 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1105 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,
1106 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1107 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1108 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1109 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1110 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1111 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1112 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1113 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1114 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1115 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1116 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1117 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1118 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1119 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1120 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1121 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1125 static void fflush_and_check(void)
1128 if (ferror(stdout) || ferror(stderr))
1129 bb_perror_msg_and_die("output error");
1132 static void quit(void) NORETURN;
1133 static void quit(void)
1136 bb_perror_msg_and_die("input error");
1141 static int bc_error(const char *fmt, ...)
1146 bb_verror_msg(fmt, p, NULL);
1150 return BC_STATUS_FAILURE;
1153 static void bc_vec_grow(BcVec *v, size_t n)
1155 size_t cap = v->cap * 2;
1156 while (cap < v->len + n) cap *= 2;
1157 v->v = xrealloc(v->v, v->size * cap);
1161 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1164 v->cap = BC_VEC_START_CAP;
1167 v->v = xmalloc(esize * BC_VEC_START_CAP);
1170 static void bc_vec_expand(BcVec *v, size_t req)
1173 v->v = xrealloc(v->v, v->size * req);
1178 static void bc_vec_npop(BcVec *v, size_t n)
1183 size_t len = v->len - n;
1184 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1188 static void bc_vec_push(BcVec *v, const void *data)
1190 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1191 memmove(v->v + (v->size * v->len), data, v->size);
1195 static void bc_vec_pushByte(BcVec *v, char data)
1197 bc_vec_push(v, &data);
1200 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1203 bc_vec_push(v, data);
1208 if (v->len == v->cap) bc_vec_grow(v, 1);
1210 ptr = v->v + v->size * idx;
1212 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1213 memmove(ptr, data, v->size);
1217 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1219 bc_vec_npop(v, v->len);
1220 bc_vec_expand(v, len + 1);
1221 memcpy(v->v, str, len);
1224 bc_vec_pushByte(v, '\0');
1227 static void bc_vec_concat(BcVec *v, const char *str)
1231 if (v->len == 0) bc_vec_pushByte(v, '\0');
1233 len = v->len + strlen(str);
1235 if (v->cap < len) bc_vec_grow(v, len - v->len);
1241 static void *bc_vec_item(const BcVec *v, size_t idx)
1243 return v->v + v->size * idx;
1246 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1248 return v->v + v->size * (v->len - idx - 1);
1251 static void bc_vec_free(void *vec)
1253 BcVec *v = (BcVec *) vec;
1254 bc_vec_npop(v, v->len);
1258 static size_t bc_map_find(const BcVec *v, const void *ptr)
1260 size_t low = 0, high = v->len;
1262 while (low < high) {
1264 size_t mid = (low + high) / 2;
1265 BcId *id = bc_vec_item(v, mid);
1266 int result = bc_id_cmp(ptr, id);
1270 else if (result < 0)
1279 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1281 BcStatus s = BC_STATUS_SUCCESS;
1283 *i = bc_map_find(v, ptr);
1286 bc_vec_push(v, ptr);
1287 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1288 s = BC_STATUS_VEC_ITEM_EXISTS;
1290 bc_vec_pushAt(v, ptr, *i);
1295 static size_t bc_map_index(const BcVec *v, const void *ptr)
1297 size_t i = bc_map_find(v, ptr);
1298 if (i >= v->len) return BC_VEC_INVALID_IDX;
1299 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1302 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1311 bc_vec_npop(vec, vec->len);
1314 #if ENABLE_FEATURE_BC_SIGNALS
1315 if (bb_got_signal) { // ^C was pressed
1317 bb_got_signal = 0; // resets G_interrupt to zero
1319 ? "\ninterrupt (type \"quit\" to exit)\n"
1320 : "\ninterrupt (type \"q\" to exit)\n"
1324 if (G.ttyin && !G_posix)
1325 fputs(prompt, stderr);
1327 #if ENABLE_FEATURE_BC_SIGNALS
1333 #if ENABLE_FEATURE_BC_SIGNALS
1334 // Both conditions appear simultaneously, check both just in case
1335 if (errno == EINTR || bb_got_signal) {
1342 quit(); // this emits error message
1344 // Note: EOF does not append '\n', therefore:
1345 // printf 'print 123\n' | bc - works
1346 // printf 'print 123' | bc - fails (syntax error)
1350 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1353 // Bad chars on this line, ignore entire line
1354 bc_error("illegal character 0x%02x", i);
1358 bc_vec_push(vec, &c);
1359 } while (i != '\n');
1360 } while (bad_chars);
1362 bc_vec_pushByte(vec, '\0');
1364 return BC_STATUS_SUCCESS;
1367 static char* bc_read_file(const char *path)
1370 size_t size = ((size_t) -1);
1373 buf = xmalloc_open_read_close(path, &size);
1375 for (i = 0; i < size; ++i) {
1377 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1389 static void bc_args(int argc, char **argv)
1394 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1395 G.flags = getopt32long(argv, "xwvsqli",
1396 "extended-register\0" No_argument "x"
1397 "warn\0" No_argument "w"
1398 "version\0" No_argument "v"
1399 "standard\0" No_argument "s"
1400 "quiet\0" No_argument "q"
1401 "mathlib\0" No_argument "l"
1402 "interactive\0" No_argument "i"
1405 G.flags = getopt32(argv, "xwvsqli");
1408 if (G.flags & BC_FLAG_V) bc_vm_info();
1409 // should not be necessary, getopt32() handles this??
1410 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1412 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1415 static void bc_num_setToZero(BcNum *n, size_t scale)
1422 static void bc_num_zero(BcNum *n)
1424 bc_num_setToZero(n, 0);
1427 static void bc_num_one(BcNum *n)
1429 bc_num_setToZero(n, 0);
1434 static void bc_num_ten(BcNum *n)
1436 bc_num_setToZero(n, 0);
1442 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1446 for (i = 0; i < len; ++i) {
1447 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1454 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1458 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1459 return BC_NUM_NEG(i + 1, c < 0);
1462 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1464 size_t i, min, a_int, b_int, diff;
1465 BcDig *max_num, *min_num;
1466 bool a_max, neg = false;
1469 if (a == b) return 0;
1470 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1471 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1481 a_int = BC_NUM_INT(a);
1482 b_int = BC_NUM_INT(b);
1484 a_max = (a->rdx > b->rdx);
1486 if (a_int != 0) return (ssize_t) a_int;
1490 diff = a->rdx - b->rdx;
1491 max_num = a->num + diff;
1496 diff = b->rdx - a->rdx;
1497 max_num = b->num + diff;
1501 cmp = bc_num_compare(max_num, min_num, b_int + min);
1502 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1504 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1505 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1511 static void bc_num_truncate(BcNum *n, size_t places)
1513 if (places == 0) return;
1519 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1523 static void bc_num_extend(BcNum *n, size_t places)
1525 size_t len = n->len + places;
1529 if (n->cap < len) bc_num_expand(n, len);
1531 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1532 memset(n->num, 0, sizeof(BcDig) * places);
1539 static void bc_num_clean(BcNum *n)
1541 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1544 else if (n->len < n->rdx)
1548 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1551 bc_num_extend(n, scale - n->rdx);
1553 bc_num_truncate(n, n->rdx - scale);
1556 if (n->len != 0) n->neg = !neg1 != !neg2;
1559 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1564 b->len = n->len - idx;
1566 a->rdx = b->rdx = 0;
1568 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1569 memcpy(a->num, n->num, idx * sizeof(BcDig));
1580 static BcStatus bc_num_shift(BcNum *n, size_t places)
1582 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1583 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1585 if (n->rdx >= places)
1588 bc_num_extend(n, places - n->rdx);
1594 return BC_STATUS_SUCCESS;
1597 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1606 return bc_num_div(&one, a, b, scale);
1609 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1611 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1612 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1615 // Because this function doesn't need to use scale (per the bc spec),
1616 // I am hijacking it to say whether it's doing an add or a subtract.
1620 if (sub && c->len) c->neg = !c->neg;
1621 return BC_STATUS_SUCCESS;
1623 else if (b->len == 0) {
1625 return BC_STATUS_SUCCESS;
1629 c->rdx = BC_MAX(a->rdx, b->rdx);
1630 min_rdx = BC_MIN(a->rdx, b->rdx);
1633 if (a->rdx > b->rdx) {
1634 diff = a->rdx - b->rdx;
1636 ptr_a = a->num + diff;
1640 diff = b->rdx - a->rdx;
1643 ptr_b = b->num + diff;
1646 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1649 a_int = BC_NUM_INT(a);
1650 b_int = BC_NUM_INT(b);
1652 if (a_int > b_int) {
1663 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1664 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1666 ptr_c[i] = (BcDig)(in % 10);
1669 for (; i < max + min_rdx; ++i, ++c->len) {
1670 in = ((int) ptr[i]) + carry;
1672 ptr_c[i] = (BcDig)(in % 10);
1675 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1677 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1680 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1683 BcNum *minuend, *subtrahend;
1685 bool aneg, bneg, neg;
1687 // Because this function doesn't need to use scale (per the bc spec),
1688 // I am hijacking it to say whether it's doing an add or a subtract.
1692 if (sub && c->len) c->neg = !c->neg;
1693 return BC_STATUS_SUCCESS;
1695 else if (b->len == 0) {
1697 return BC_STATUS_SUCCESS;
1702 a->neg = b->neg = false;
1704 cmp = bc_num_cmp(a, b);
1710 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1711 return BC_STATUS_SUCCESS;
1720 if (sub) neg = !neg;
1725 bc_num_copy(c, minuend);
1728 if (c->rdx < subtrahend->rdx) {
1729 bc_num_extend(c, subtrahend->rdx - c->rdx);
1733 start = c->rdx - subtrahend->rdx;
1735 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1739 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1742 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1747 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1748 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1749 bool aone = BC_NUM_ONE(a);
1751 if (a->len == 0 || b->len == 0) {
1753 return BC_STATUS_SUCCESS;
1755 else if (aone || BC_NUM_ONE(b)) {
1756 bc_num_copy(c, aone ? b : a);
1757 return BC_STATUS_SUCCESS;
1760 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1761 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1763 bc_num_expand(c, a->len + b->len + 1);
1765 memset(c->num, 0, sizeof(BcDig) * c->cap);
1766 c->len = carry = len = 0;
1768 for (i = 0; i < b->len; ++i) {
1770 for (j = 0; j < a->len; ++j) {
1771 int in = (int) c->num[i + j];
1772 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1774 c->num[i + j] = (BcDig)(in % 10);
1777 c->num[i + j] += (BcDig) carry;
1778 len = BC_MAX(len, i + j + !!carry);
1784 return BC_STATUS_SUCCESS;
1787 bc_num_init(&l1, max);
1788 bc_num_init(&h1, max);
1789 bc_num_init(&l2, max);
1790 bc_num_init(&h2, max);
1791 bc_num_init(&m1, max);
1792 bc_num_init(&m2, max);
1793 bc_num_init(&z0, max);
1794 bc_num_init(&z1, max);
1795 bc_num_init(&z2, max);
1796 bc_num_init(&temp, max + max);
1798 bc_num_split(a, max2, &l1, &h1);
1799 bc_num_split(b, max2, &l2, &h2);
1801 s = bc_num_add(&h1, &l1, &m1, 0);
1803 s = bc_num_add(&h2, &l2, &m2, 0);
1806 s = bc_num_k(&h1, &h2, &z0);
1808 s = bc_num_k(&m1, &m2, &z1);
1810 s = bc_num_k(&l1, &l2, &z2);
1813 s = bc_num_sub(&z1, &z0, &temp, 0);
1815 s = bc_num_sub(&temp, &z2, &z1, 0);
1818 s = bc_num_shift(&z0, max2 * 2);
1820 s = bc_num_shift(&z1, max2);
1822 s = bc_num_add(&z0, &z1, &temp, 0);
1824 s = bc_num_add(&temp, &z2, c, 0);
1840 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1844 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1846 scale = BC_MAX(scale, a->rdx);
1847 scale = BC_MAX(scale, b->rdx);
1848 scale = BC_MIN(a->rdx + b->rdx, scale);
1849 maxrdx = BC_MAX(maxrdx, scale);
1851 bc_num_init(&cpa, a->len);
1852 bc_num_init(&cpb, b->len);
1854 bc_num_copy(&cpa, a);
1855 bc_num_copy(&cpb, b);
1856 cpa.neg = cpb.neg = false;
1858 s = bc_num_shift(&cpa, maxrdx);
1860 s = bc_num_shift(&cpb, maxrdx);
1862 s = bc_num_k(&cpa, &cpb, c);
1866 bc_num_expand(c, c->len + maxrdx);
1868 if (c->len < maxrdx) {
1869 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1874 bc_num_retireMul(c, scale, a->neg, b->neg);
1882 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1884 BcStatus s = BC_STATUS_SUCCESS;
1891 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1892 else if (a->len == 0) {
1893 bc_num_setToZero(c, scale);
1894 return BC_STATUS_SUCCESS;
1896 else if (BC_NUM_ONE(b)) {
1898 bc_num_retireMul(c, scale, a->neg, b->neg);
1899 return BC_STATUS_SUCCESS;
1902 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1903 bc_num_copy(&cp, a);
1907 bc_num_expand(&cp, len + 2);
1908 bc_num_extend(&cp, len - cp.len);
1911 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1913 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1915 if (b->rdx == b->len) {
1916 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1920 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1922 // We want an extra zero in front to make things simpler.
1923 cp.num[cp.len++] = 0;
1926 bc_num_expand(c, cp.len);
1929 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1934 for (i = end - 1; !s && i < end; --i) {
1936 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1937 bc_num_subArrays(n, p, len);
1941 bc_num_retireMul(c, scale, a->neg, b->neg);
1944 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1947 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1948 BcNum *restrict d, size_t scale, size_t ts)
1954 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1957 bc_num_setToZero(d, ts);
1958 return BC_STATUS_SUCCESS;
1961 bc_num_init(&temp, d->cap);
1962 bc_num_d(a, b, c, scale);
1964 if (scale != 0) scale = ts;
1966 s = bc_num_m(c, b, &temp, scale);
1968 s = bc_num_sub(a, &temp, d, scale);
1971 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1974 bc_num_retireMul(d, ts, a->neg, b->neg);
1982 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1986 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1988 bc_num_init(&c1, len);
1989 s = bc_num_r(a, b, &c1, c, scale, ts);
1995 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1997 BcStatus s = BC_STATUS_SUCCESS;
2000 size_t i, powrdx, resrdx;
2003 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2007 return BC_STATUS_SUCCESS;
2009 else if (a->len == 0) {
2010 bc_num_setToZero(c, scale);
2011 return BC_STATUS_SUCCESS;
2013 else if (BC_NUM_ONE(b)) {
2017 s = bc_num_inv(a, c, scale);
2024 s = bc_num_ulong(b, &pow);
2027 bc_num_init(©, a->len);
2028 bc_num_copy(©, a);
2030 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2034 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2036 s = bc_num_mul(©, ©, ©, powrdx);
2040 bc_num_copy(c, ©);
2042 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2045 s = bc_num_mul(©, ©, ©, powrdx);
2050 s = bc_num_mul(c, ©, c, resrdx);
2056 s = bc_num_inv(c, c, scale);
2060 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2062 // We can't use bc_num_clean() here.
2063 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2064 if (zero) bc_num_setToZero(c, scale);
2071 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2072 BcNumBinaryOp op, size_t req)
2075 BcNum num2, *ptr_a, *ptr_b;
2080 memcpy(ptr_a, c, sizeof(BcNum));
2089 memcpy(ptr_b, c, sizeof(BcNum));
2097 bc_num_init(c, req);
2099 bc_num_expand(c, req);
2101 s = op(ptr_a, ptr_b, c, scale);
2103 if (init) bc_num_free(&num2);
2108 static bool bc_num_strValid(const char *val, size_t base)
2111 bool small, radix = false;
2112 size_t i, len = strlen(val);
2114 if (!len) return true;
2117 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2119 for (i = 0; i < len; ++i) {
2125 if (radix) return false;
2131 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2138 static void bc_num_parseDecimal(BcNum *n, const char *val)
2144 for (i = 0; val[i] == '0'; ++i);
2151 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2152 bc_num_expand(n, len);
2155 ptr = strchr(val, '.');
2157 // Explicitly test for NULL here to produce either a 0 or 1.
2158 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2161 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2162 n->num[n->len] = val[i] - '0';
2166 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2169 BcNum temp, mult, result;
2173 size_t i, digits, len = strlen(val);
2177 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2180 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2181 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2183 for (i = 0; i < len; ++i) {
2186 if (c == '.') break;
2188 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2190 s = bc_num_mul(n, base, &mult, 0);
2191 if (s) goto int_err;
2192 bc_num_ulong2num(&temp, v);
2193 s = bc_num_add(&mult, &temp, n, 0);
2194 if (s) goto int_err;
2199 if (c == 0) goto int_err;
2202 bc_num_init(&result, base->len);
2203 bc_num_zero(&result);
2206 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2211 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2213 s = bc_num_mul(&result, base, &result, 0);
2215 bc_num_ulong2num(&temp, v);
2216 s = bc_num_add(&result, &temp, &result, 0);
2218 s = bc_num_mul(&mult, base, &mult, 0);
2222 s = bc_num_div(&result, &mult, &result, digits);
2224 s = bc_num_add(n, &result, n, digits);
2228 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2234 bc_num_free(&result);
2240 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2242 if (*nchars == line_len - 1) {
2250 static void bc_num_printChar(size_t num, size_t width, bool radix,
2251 size_t *nchars, size_t line_len)
2253 (void) radix, (void) line_len;
2254 bb_putchar((char) num);
2255 *nchars = *nchars + width;
2259 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2260 size_t *nchars, size_t line_len)
2264 bc_num_printNewline(nchars, line_len);
2265 bb_putchar(radix ? '.' : ' ');
2268 bc_num_printNewline(nchars, line_len);
2269 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2272 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2274 bc_num_printNewline(nchars, line_len);
2277 bb_putchar(((char) dig) + '0');
2281 static void bc_num_printHex(size_t num, size_t width, bool radix,
2282 size_t *nchars, size_t line_len)
2285 bc_num_printNewline(nchars, line_len);
2290 bc_num_printNewline(nchars, line_len);
2291 bb_putchar(bb_hexdigits_upcase[num]);
2292 *nchars = *nchars + width;
2295 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2297 size_t i, rdx = n->rdx - 1;
2299 if (n->neg) bb_putchar('-');
2300 (*nchars) += n->neg;
2302 for (i = n->len - 1; i < n->len; --i)
2303 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2306 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2307 size_t *nchars, size_t len, BcNumDigitOp print)
2311 BcNum intp, fracp, digit, frac_len;
2312 unsigned long dig, *ptr;
2317 print(0, width, false, nchars, len);
2318 return BC_STATUS_SUCCESS;
2321 bc_vec_init(&stack, sizeof(long), NULL);
2322 bc_num_init(&intp, n->len);
2323 bc_num_init(&fracp, n->rdx);
2324 bc_num_init(&digit, width);
2325 bc_num_init(&frac_len, BC_NUM_INT(n));
2326 bc_num_copy(&intp, n);
2327 bc_num_one(&frac_len);
2329 bc_num_truncate(&intp, intp.rdx);
2330 s = bc_num_sub(n, &intp, &fracp, 0);
2333 while (intp.len != 0) {
2334 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2336 s = bc_num_ulong(&digit, &dig);
2338 bc_vec_push(&stack, &dig);
2341 for (i = 0; i < stack.len; ++i) {
2342 ptr = bc_vec_item_rev(&stack, i);
2343 print(*ptr, width, false, nchars, len);
2346 if (!n->rdx) goto err;
2348 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2349 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2351 s = bc_num_ulong(&fracp, &dig);
2353 bc_num_ulong2num(&intp, dig);
2354 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2356 print(dig, width, radix, nchars, len);
2357 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2362 bc_num_free(&frac_len);
2363 bc_num_free(&digit);
2364 bc_num_free(&fracp);
2366 bc_vec_free(&stack);
2370 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2371 size_t *nchars, size_t line_len)
2378 if (neg) bb_putchar('-');
2383 if (base_t <= BC_NUM_MAX_IBASE) {
2385 print = bc_num_printHex;
2388 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2389 print = bc_num_printDigits;
2392 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2399 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2401 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2405 static void bc_num_init(BcNum *n, size_t req)
2407 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2408 memset(n, 0, sizeof(BcNum));
2409 n->num = xmalloc(req);
2413 static void bc_num_expand(BcNum *n, size_t req)
2415 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2417 n->num = xrealloc(n->num, req);
2422 static void bc_num_free(void *num)
2424 free(((BcNum *) num)->num);
2427 static void bc_num_copy(BcNum *d, BcNum *s)
2430 bc_num_expand(d, s->cap);
2434 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2438 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2441 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2444 bc_num_parseDecimal(n, val);
2446 bc_num_parseBase(n, val, base);
2448 return BC_STATUS_SUCCESS;
2451 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2452 size_t *nchars, size_t line_len)
2454 BcStatus s = BC_STATUS_SUCCESS;
2456 bc_num_printNewline(nchars, line_len);
2462 else if (base_t == 10)
2463 bc_num_printDecimal(n, nchars, line_len);
2465 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2475 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2480 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2482 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2484 unsigned long prev = *result, powprev = pow;
2486 *result += ((unsigned long) n->num[i]) * pow;
2489 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2492 return BC_STATUS_SUCCESS;
2495 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2503 if (val == 0) return;
2505 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2506 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2509 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2511 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2513 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2516 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2518 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2520 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2523 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2525 size_t req = BC_NUM_MREQ(a, b, scale);
2526 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2529 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2531 size_t req = BC_NUM_MREQ(a, b, scale);
2532 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2535 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2537 size_t req = BC_NUM_MREQ(a, b, scale);
2538 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2541 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2543 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2546 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2549 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2550 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2551 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2553 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2554 bc_num_expand(b, req);
2557 bc_num_setToZero(b, scale);
2558 return BC_STATUS_SUCCESS;
2561 return BC_STATUS_MATH_NEGATIVE;
2562 else if (BC_NUM_ONE(a)) {
2564 bc_num_extend(b, scale);
2565 return BC_STATUS_SUCCESS;
2568 scale = BC_MAX(scale, a->rdx) + 1;
2569 len = a->len + scale;
2571 bc_num_init(&num1, len);
2572 bc_num_init(&num2, len);
2573 bc_num_init(&half, BC_NUM_DEF_SIZE);
2579 bc_num_init(&f, len);
2580 bc_num_init(&fprime, len);
2586 pow = BC_NUM_INT(a);
2595 pow -= 2 - (pow & 1);
2597 bc_num_extend(x0, pow);
2599 // Make sure to move the radix back.
2603 x0->rdx = digs = digs1 = 0;
2605 len = BC_NUM_INT(x0) + resrdx - 1;
2607 while (cmp != 0 || digs < len) {
2609 s = bc_num_div(a, x0, &f, resrdx);
2611 s = bc_num_add(x0, &f, &fprime, resrdx);
2613 s = bc_num_mul(&fprime, &half, x1, resrdx);
2616 cmp = bc_num_cmp(x1, x0);
2617 digs = x1->len - (unsigned long long) llabs(cmp);
2619 if (cmp == cmp2 && digs == digs1)
2624 resrdx += times > 4;
2637 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2640 bc_num_free(&fprime);
2648 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2654 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2657 memcpy(&num2, c, sizeof(BcNum));
2659 bc_num_init(c, len);
2664 bc_num_expand(c, len);
2667 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2669 if (init) bc_num_free(&num2);
2675 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2678 BcNum base, exp, two, temp;
2680 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2681 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2682 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2684 bc_num_expand(d, c->len);
2685 bc_num_init(&base, c->len);
2686 bc_num_init(&exp, b->len);
2687 bc_num_init(&two, BC_NUM_DEF_SIZE);
2688 bc_num_init(&temp, b->len);
2694 s = bc_num_rem(a, c, &base, 0);
2696 bc_num_copy(&exp, b);
2698 while (exp.len != 0) {
2700 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2703 if (BC_NUM_ONE(&temp)) {
2704 s = bc_num_mul(d, &base, &temp, 0);
2706 s = bc_num_rem(&temp, c, d, 0);
2710 s = bc_num_mul(&base, &base, &temp, 0);
2712 s = bc_num_rem(&temp, c, &base, 0);
2725 static int bc_id_cmp(const void *e1, const void *e2)
2727 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2730 static void bc_id_free(void *id)
2732 free(((BcId *) id)->name);
2735 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2740 for (i = 0; i < f->autos.len; ++i) {
2741 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2742 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2748 bc_vec_push(&f->autos, &a);
2750 return BC_STATUS_SUCCESS;
2753 static void bc_func_init(BcFunc *f)
2755 bc_vec_init(&f->code, sizeof(char), NULL);
2756 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2757 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2761 static void bc_func_free(void *func)
2763 BcFunc *f = (BcFunc *) func;
2764 bc_vec_free(&f->code);
2765 bc_vec_free(&f->autos);
2766 bc_vec_free(&f->labels);
2769 static void bc_array_init(BcVec *a, bool nums)
2772 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2774 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2775 bc_array_expand(a, 1);
2778 static void bc_array_copy(BcVec *d, const BcVec *s)
2782 bc_vec_npop(d, d->len);
2783 bc_vec_expand(d, s->cap);
2786 for (i = 0; i < s->len; ++i) {
2787 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2788 bc_num_init(dnum, snum->len);
2789 bc_num_copy(dnum, snum);
2793 static void bc_array_expand(BcVec *a, size_t len)
2797 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2798 while (len > a->len) {
2799 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2800 bc_vec_push(a, &data.n);
2804 while (len > a->len) {
2805 bc_array_init(&data.v, true);
2806 bc_vec_push(a, &data.v);
2811 static void bc_string_free(void *string)
2813 free(*((char **) string));
2817 static void bc_result_copy(BcResult *d, BcResult *src)
2823 case BC_RESULT_TEMP:
2824 case BC_RESULT_IBASE:
2825 case BC_RESULT_SCALE:
2826 case BC_RESULT_OBASE:
2828 bc_num_init(&d->d.n, src->d.n.len);
2829 bc_num_copy(&d->d.n, &src->d.n);
2834 case BC_RESULT_ARRAY:
2835 case BC_RESULT_ARRAY_ELEM:
2837 d->d.id.name = xstrdup(src->d.id.name);
2841 case BC_RESULT_CONSTANT:
2842 case BC_RESULT_LAST:
2846 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2853 static void bc_result_free(void *result)
2855 BcResult *r = (BcResult *) result;
2859 case BC_RESULT_TEMP:
2860 case BC_RESULT_IBASE:
2861 case BC_RESULT_SCALE:
2862 case BC_RESULT_OBASE:
2864 bc_num_free(&r->d.n);
2869 case BC_RESULT_ARRAY:
2870 case BC_RESULT_ARRAY_ELEM:
2884 static void bc_lex_lineComment(BcLex *l)
2886 l->t.t = BC_LEX_WHITESPACE;
2887 while (l->i < l->len && l->buf[l->i++] != '\n');
2891 static void bc_lex_whitespace(BcLex *l)
2894 l->t.t = BC_LEX_WHITESPACE;
2895 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2898 static BcStatus bc_lex_number(BcLex *l, char start)
2900 const char *buf = l->buf + l->i;
2901 size_t len, hits = 0, bslashes = 0, i = 0, j;
2903 bool last_pt, pt = start == '.';
2906 l->t.t = BC_LEX_NUMBER;
2908 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2909 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2923 len = i + 1 * !last_pt - bslashes * 2;
2924 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2926 bc_vec_npop(&l->t.v, l->t.v.len);
2927 bc_vec_expand(&l->t.v, len + 1);
2928 bc_vec_push(&l->t.v, &start);
2930 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2934 // If we have hit a backslash, skip it. We don't have
2935 // to check for a newline because it's guaranteed.
2936 if (hits < bslashes && c == '\\') {
2942 bc_vec_push(&l->t.v, &c);
2945 bc_vec_pushByte(&l->t.v, '\0');
2948 return BC_STATUS_SUCCESS;
2951 static BcStatus bc_lex_name(BcLex *l)
2954 const char *buf = l->buf + l->i - 1;
2957 l->t.t = BC_LEX_NAME;
2959 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2961 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2962 bc_vec_string(&l->t.v, i, buf);
2964 // Increment the index. We minus 1 because it has already been incremented.
2967 return BC_STATUS_SUCCESS;
2970 static void bc_lex_init(BcLex *l, BcLexNext next)
2973 bc_vec_init(&l->t.v, sizeof(char), NULL);
2976 static void bc_lex_free(BcLex *l)
2978 bc_vec_free(&l->t.v);
2981 static void bc_lex_file(BcLex *l, const char *file)
2988 static BcStatus bc_lex_next(BcLex *l)
2993 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
2995 l->line += l->newline;
2996 l->t.t = BC_LEX_EOF;
2998 l->newline = (l->i == l->len);
2999 if (l->newline) return BC_STATUS_SUCCESS;
3001 // Loop until failure or we don't have whitespace. This
3002 // is so the parser doesn't get inundated with whitespace.
3005 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3010 static BcStatus bc_lex_text(BcLex *l, const char *text)
3014 l->len = strlen(text);
3015 l->t.t = l->t.last = BC_LEX_INVALID;
3016 return bc_lex_next(l);
3020 static BcStatus bc_lex_identifier(BcLex *l)
3024 const char *buf = l->buf + l->i - 1;
3026 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3028 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3030 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3032 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3034 if (!bc_lex_kws[i].posix) {
3035 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3036 bc_lex_kws[i].name);
3040 // We minus 1 because the index has already been incremented.
3042 return BC_STATUS_SUCCESS;
3049 if (l->t.v.len - 1 > 1)
3050 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3055 static BcStatus bc_lex_string(BcLex *l)
3057 size_t len, nls = 0, i = l->i;
3060 l->t.t = BC_LEX_STR;
3062 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3066 return BC_STATUS_LEX_NO_STRING_END;
3070 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3071 bc_vec_string(&l->t.v, len, l->buf + l->i);
3076 return BC_STATUS_SUCCESS;
3079 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3081 if (l->buf[l->i] == '=') {
3089 static BcStatus bc_lex_comment(BcLex *l)
3092 const char *buf = l->buf;
3096 l->t.t = BC_LEX_WHITESPACE;
3098 for (i = ++l->i; !end; i += !end) {
3100 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3102 if (c == 0 || buf[i + 1] == '\0') {
3104 return BC_STATUS_LEX_NO_COMMENT_END;
3107 end = buf[i + 1] == '/';
3113 return BC_STATUS_SUCCESS;
3116 static BcStatus bc_lex_token(BcLex *l)
3118 BcStatus s = BC_STATUS_SUCCESS;
3119 char c = l->buf[l->i++], c2;
3121 // This is the workhorse of the lexer.
3128 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3138 bc_lex_whitespace(l);
3144 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3146 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3147 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3156 s = bc_lex_string(l);
3162 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3165 bc_lex_lineComment(l);
3172 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3181 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3185 l->t.t = BC_LEX_OP_BOOL_AND;
3188 l->t.t = BC_LEX_INVALID;
3189 s = bc_error("bad character '%c'", '&');
3198 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3204 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3213 l->t.t = BC_LEX_OP_INC;
3216 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3222 l->t.t = BC_LEX_COMMA;
3231 l->t.t = BC_LEX_OP_DEC;
3234 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3240 if (isdigit(l->buf[l->i]))
3241 s = bc_lex_number(l, c);
3243 l->t.t = BC_LEX_KEY_LAST;
3244 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3253 s = bc_lex_comment(l);
3255 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3276 s = bc_lex_number(l, c);
3282 l->t.t = BC_LEX_SCOLON;
3288 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3294 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3300 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3307 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3313 if (l->buf[l->i] == '\n') {
3314 l->t.t = BC_LEX_WHITESPACE;
3318 s = bc_error("bad character '%c'", c);
3324 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3355 s = bc_lex_identifier(l);
3362 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3372 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3376 l->t.t = BC_LEX_OP_BOOL_OR;
3379 l->t.t = BC_LEX_INVALID;
3380 s = bc_error("bad character '%c'", c);
3388 l->t.t = BC_LEX_INVALID;
3389 s = bc_error("bad character '%c'", c);
3399 static BcStatus dc_lex_register(BcLex *l)
3401 BcStatus s = BC_STATUS_SUCCESS;
3403 if (isspace(l->buf[l->i - 1])) {
3404 bc_lex_whitespace(l);
3407 s = BC_STATUS_LEX_EXTENDED_REG;
3412 bc_vec_npop(&l->t.v, l->t.v.len);
3413 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3414 bc_vec_pushByte(&l->t.v, '\0');
3415 l->t.t = BC_LEX_NAME;
3421 static BcStatus dc_lex_string(BcLex *l)
3423 size_t depth = 1, nls = 0, i = l->i;
3426 l->t.t = BC_LEX_STR;
3427 bc_vec_npop(&l->t.v, l->t.v.len);
3429 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3431 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3432 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3435 if (depth) bc_vec_push(&l->t.v, &c);
3440 return BC_STATUS_LEX_NO_STRING_END;
3443 bc_vec_pushByte(&l->t.v, '\0');
3444 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3449 return BC_STATUS_SUCCESS;
3452 static BcStatus dc_lex_token(BcLex *l)
3454 BcStatus s = BC_STATUS_SUCCESS;
3455 char c = l->buf[l->i++], c2;
3458 for (i = 0; i < dc_lex_regs_len; ++i) {
3459 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3462 if (c >= '%' && c <= '~' &&
3463 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3468 // This is the workhorse of the lexer.
3473 l->t.t = BC_LEX_EOF;
3484 l->newline = (c == '\n');
3485 bc_lex_whitespace(l);
3494 l->t.t = BC_LEX_OP_REL_NE;
3496 l->t.t = BC_LEX_OP_REL_LE;
3498 l->t.t = BC_LEX_OP_REL_GE;
3500 return bc_error("bad character '%c'", c);
3508 bc_lex_lineComment(l);
3514 if (isdigit(l->buf[l->i]))
3515 s = bc_lex_number(l, c);
3517 s = bc_error("bad character '%c'", c);
3538 s = bc_lex_number(l, c);
3544 s = dc_lex_string(l);
3550 l->t.t = BC_LEX_INVALID;
3551 s = bc_error("bad character '%c'", c);
3560 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3562 bc_program_addFunc(name, idx);
3563 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3566 static void bc_parse_pushName(BcParse *p, char *name)
3568 size_t i = 0, len = strlen(name);
3570 for (; i < len; ++i) bc_parse_push(p, name[i]);
3571 bc_parse_push(p, BC_PARSE_STREND);
3576 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3578 unsigned char amt, i, nums[sizeof(size_t)];
3580 for (amt = 0; idx; ++amt) {
3581 nums[amt] = (char) idx;
3582 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3585 bc_parse_push(p, amt);
3586 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3589 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3591 char *num = xstrdup(p->l.t.v.v);
3592 size_t idx = G.prog.consts.len;
3594 bc_vec_push(&G.prog.consts, &num);
3596 bc_parse_push(p, BC_INST_NUM);
3597 bc_parse_pushIndex(p, idx);
3600 (*prev) = BC_INST_NUM;
3603 static BcStatus bc_parse_text(BcParse *p, const char *text)
3607 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3609 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3610 p->l.t.t = BC_LEX_INVALID;
3613 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3616 return bc_lex_text(&p->l, text);
3619 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3621 if (p->fidx != BC_PROG_MAIN) {
3623 p->func->nparams = 0;
3624 bc_vec_npop(&p->func->code, p->func->code.len);
3625 bc_vec_npop(&p->func->autos, p->func->autos.len);
3626 bc_vec_npop(&p->func->labels, p->func->labels.len);
3628 bc_parse_updateFunc(p, BC_PROG_MAIN);
3632 p->l.t.t = BC_LEX_EOF;
3633 p->auto_part = (p->nbraces = 0);
3635 bc_vec_npop(&p->flags, p->flags.len - 1);
3636 bc_vec_npop(&p->exits, p->exits.len);
3637 bc_vec_npop(&p->conds, p->conds.len);
3638 bc_vec_npop(&p->ops, p->ops.len);
3640 return bc_program_reset(s);
3643 static void bc_parse_free(BcParse *p)
3645 bc_vec_free(&p->flags);
3646 bc_vec_free(&p->exits);
3647 bc_vec_free(&p->conds);
3648 bc_vec_free(&p->ops);
3652 static void bc_parse_create(BcParse *p, size_t func,
3653 BcParseParse parse, BcLexNext next)
3655 memset(p, 0, sizeof(BcParse));
3657 bc_lex_init(&p->l, next);
3658 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3659 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3660 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3661 bc_vec_pushByte(&p->flags, 0);
3662 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3665 // p->auto_part = p->nbraces = 0; - already is
3666 bc_parse_updateFunc(p, func);
3670 static BcStatus bc_parse_else(BcParse *p);
3671 static BcStatus bc_parse_stmt(BcParse *p);
3673 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3674 size_t *nexprs, bool next)
3676 BcStatus s = BC_STATUS_SUCCESS;
3678 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3679 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3681 while (p->ops.len > start) {
3683 t = BC_PARSE_TOP_OP(p);
3684 if (t == BC_LEX_LPAREN) break;
3686 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3687 if (l >= r && (l != r || !left)) break;
3689 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3690 bc_vec_pop(&p->ops);
3691 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3694 bc_vec_push(&p->ops, &type);
3695 if (next) s = bc_lex_next(&p->l);
3700 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3704 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3705 top = BC_PARSE_TOP_OP(p);
3707 while (top != BC_LEX_LPAREN) {
3709 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3711 bc_vec_pop(&p->ops);
3712 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3714 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3715 top = BC_PARSE_TOP_OP(p);
3718 bc_vec_pop(&p->ops);
3720 return bc_lex_next(&p->l);
3723 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3729 s = bc_lex_next(&p->l);
3732 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3734 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3735 s = bc_parse_expr(p, flags, bc_parse_next_param);
3738 comma = p->l.t.t == BC_LEX_COMMA;
3740 s = bc_lex_next(&p->l);
3745 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3746 bc_parse_push(p, BC_INST_CALL);
3747 bc_parse_pushIndex(p, nparams);
3749 return BC_STATUS_SUCCESS;
3752 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3755 BcId entry, *entry_ptr;
3760 s = bc_parse_params(p, flags);
3763 if (p->l.t.t != BC_LEX_RPAREN) {
3764 s = BC_STATUS_PARSE_BAD_TOKEN;
3768 idx = bc_map_index(&G.prog.fn_map, &entry);
3770 if (idx == BC_VEC_INVALID_IDX) {
3771 name = xstrdup(entry.name);
3772 bc_parse_addFunc(p, name, &idx);
3773 idx = bc_map_index(&G.prog.fn_map, &entry);
3779 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3780 bc_parse_pushIndex(p, entry_ptr->idx);
3782 return bc_lex_next(&p->l);
3789 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3794 name = xstrdup(p->l.t.v.v);
3795 s = bc_lex_next(&p->l);
3798 if (p->l.t.t == BC_LEX_LBRACKET) {
3800 s = bc_lex_next(&p->l);
3803 if (p->l.t.t == BC_LEX_RBRACKET) {
3805 if (!(flags & BC_PARSE_ARRAY)) {
3806 s = BC_STATUS_PARSE_BAD_EXP;
3810 *type = BC_INST_ARRAY;
3814 *type = BC_INST_ARRAY_ELEM;
3816 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3817 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3821 s = bc_lex_next(&p->l);
3823 bc_parse_push(p, *type);
3824 bc_parse_pushName(p, name);
3826 else if (p->l.t.t == BC_LEX_LPAREN) {
3828 if (flags & BC_PARSE_NOCALL) {
3829 s = BC_STATUS_PARSE_BAD_TOKEN;
3833 *type = BC_INST_CALL;
3834 s = bc_parse_call(p, name, flags);
3837 *type = BC_INST_VAR;
3838 bc_parse_push(p, BC_INST_VAR);
3839 bc_parse_pushName(p, name);
3849 static BcStatus bc_parse_read(BcParse *p)
3853 s = bc_lex_next(&p->l);
3855 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3857 s = bc_lex_next(&p->l);
3859 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3861 bc_parse_push(p, BC_INST_READ);
3863 return bc_lex_next(&p->l);
3866 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3871 s = bc_lex_next(&p->l);
3873 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3875 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3877 s = bc_lex_next(&p->l);
3880 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3883 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3885 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3886 bc_parse_push(p, *prev);
3888 return bc_lex_next(&p->l);
3891 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3895 s = bc_lex_next(&p->l);
3898 if (p->l.t.t != BC_LEX_LPAREN) {
3899 *type = BC_INST_SCALE;
3900 bc_parse_push(p, BC_INST_SCALE);
3901 return BC_STATUS_SUCCESS;
3904 *type = BC_INST_SCALE_FUNC;
3905 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3907 s = bc_lex_next(&p->l);
3910 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3912 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3913 bc_parse_push(p, BC_INST_SCALE_FUNC);
3915 return bc_lex_next(&p->l);
3918 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3919 size_t *nexprs, uint8_t flags)
3924 BcInst etype = *prev;
3926 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3927 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3928 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3930 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3931 bc_parse_push(p, inst);
3932 s = bc_lex_next(&p->l);
3936 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3939 s = bc_lex_next(&p->l);
3943 // Because we parse the next part of the expression
3944 // right here, we need to increment this.
3945 *nexprs = *nexprs + 1;
3951 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3955 case BC_LEX_KEY_IBASE:
3956 case BC_LEX_KEY_LAST:
3957 case BC_LEX_KEY_OBASE:
3959 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3960 s = bc_lex_next(&p->l);
3964 case BC_LEX_KEY_SCALE:
3966 s = bc_lex_next(&p->l);
3968 if (p->l.t.t == BC_LEX_LPAREN)
3969 s = BC_STATUS_PARSE_BAD_TOKEN;
3971 bc_parse_push(p, BC_INST_SCALE);
3977 s = BC_STATUS_PARSE_BAD_TOKEN;
3982 if (!s) bc_parse_push(p, inst);
3988 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3989 bool rparen, size_t *nexprs)
3993 BcInst etype = *prev;
3995 s = bc_lex_next(&p->l);
3998 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3999 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4002 *prev = BC_PARSE_TOKEN_INST(type);
4004 // We can just push onto the op stack because this is the largest
4005 // precedence operator that gets pushed. Inc/dec does not.
4006 if (type != BC_LEX_OP_MINUS)
4007 bc_vec_push(&p->ops, &type);
4009 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4014 static BcStatus bc_parse_string(BcParse *p, char inst)
4016 char *str = xstrdup(p->l.t.v.v);
4018 bc_parse_push(p, BC_INST_STR);
4019 bc_parse_pushIndex(p, G.prog.strs.len);
4020 bc_vec_push(&G.prog.strs, &str);
4021 bc_parse_push(p, inst);
4023 return bc_lex_next(&p->l);
4026 static BcStatus bc_parse_print(BcParse *p)
4032 s = bc_lex_next(&p->l);
4037 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4038 return BC_STATUS_PARSE_BAD_PRINT;
4040 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4042 if (type == BC_LEX_STR)
4043 s = bc_parse_string(p, BC_INST_PRINT_POP);
4045 s = bc_parse_expr(p, 0, bc_parse_next_print);
4047 bc_parse_push(p, BC_INST_PRINT_POP);
4052 comma = p->l.t.t == BC_LEX_COMMA;
4053 if (comma) s = bc_lex_next(&p->l);
4058 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4060 return bc_lex_next(&p->l);
4063 static BcStatus bc_parse_return(BcParse *p)
4069 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4071 s = bc_lex_next(&p->l);
4075 paren = t == BC_LEX_LPAREN;
4077 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4078 bc_parse_push(p, BC_INST_RET0);
4081 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4082 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4084 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4085 bc_parse_push(p, BC_INST_RET0);
4086 s = bc_lex_next(&p->l);
4090 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4091 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4095 bc_parse_push(p, BC_INST_RET);
4101 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4103 BcStatus s = BC_STATUS_SUCCESS;
4105 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4106 return BC_STATUS_PARSE_BAD_TOKEN;
4110 if (p->l.t.t == BC_LEX_RBRACE) {
4111 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4113 s = bc_lex_next(&p->l);
4117 return BC_STATUS_PARSE_BAD_TOKEN;
4120 if (BC_PARSE_IF(p)) {
4124 while (p->l.t.t == BC_LEX_NLINE) {
4125 s = bc_lex_next(&p->l);
4129 bc_vec_pop(&p->flags);
4131 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4132 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4134 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4136 else if (BC_PARSE_ELSE(p)) {
4141 bc_vec_pop(&p->flags);
4143 ip = bc_vec_top(&p->exits);
4144 label = bc_vec_item(&p->func->labels, ip->idx);
4145 *label = p->func->code.len;
4147 bc_vec_pop(&p->exits);
4149 else if (BC_PARSE_FUNC_INNER(p)) {
4150 bc_parse_push(p, BC_INST_RET0);
4151 bc_parse_updateFunc(p, BC_PROG_MAIN);
4152 bc_vec_pop(&p->flags);
4156 BcInstPtr *ip = bc_vec_top(&p->exits);
4157 size_t *label = bc_vec_top(&p->conds);
4159 bc_parse_push(p, BC_INST_JUMP);
4160 bc_parse_pushIndex(p, *label);
4162 label = bc_vec_item(&p->func->labels, ip->idx);
4163 *label = p->func->code.len;
4165 bc_vec_pop(&p->flags);
4166 bc_vec_pop(&p->exits);
4167 bc_vec_pop(&p->conds);
4173 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4175 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4176 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4177 flags |= BC_PARSE_FLAG_BODY;
4178 bc_vec_push(&p->flags, &flags);
4181 static void bc_parse_noElse(BcParse *p)
4185 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4187 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4189 ip = bc_vec_top(&p->exits);
4190 label = bc_vec_item(&p->func->labels, ip->idx);
4191 *label = p->func->code.len;
4193 bc_vec_pop(&p->exits);
4196 static BcStatus bc_parse_if(BcParse *p)
4201 s = bc_lex_next(&p->l);
4203 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4205 s = bc_lex_next(&p->l);
4207 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4209 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4211 s = bc_lex_next(&p->l);
4213 bc_parse_push(p, BC_INST_JUMP_ZERO);
4215 ip.idx = p->func->labels.len;
4216 ip.func = ip.len = 0;
4218 bc_parse_pushIndex(p, ip.idx);
4219 bc_vec_push(&p->exits, &ip);
4220 bc_vec_push(&p->func->labels, &ip.idx);
4221 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4223 return BC_STATUS_SUCCESS;
4226 static BcStatus bc_parse_else(BcParse *p)
4230 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4232 ip.idx = p->func->labels.len;
4233 ip.func = ip.len = 0;
4235 bc_parse_push(p, BC_INST_JUMP);
4236 bc_parse_pushIndex(p, ip.idx);
4240 bc_vec_push(&p->exits, &ip);
4241 bc_vec_push(&p->func->labels, &ip.idx);
4242 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4244 return bc_lex_next(&p->l);
4247 static BcStatus bc_parse_while(BcParse *p)
4252 s = bc_lex_next(&p->l);
4254 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4255 s = bc_lex_next(&p->l);
4258 ip.idx = p->func->labels.len;
4260 bc_vec_push(&p->func->labels, &p->func->code.len);
4261 bc_vec_push(&p->conds, &ip.idx);
4263 ip.idx = p->func->labels.len;
4267 bc_vec_push(&p->exits, &ip);
4268 bc_vec_push(&p->func->labels, &ip.idx);
4270 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4272 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4273 s = bc_lex_next(&p->l);
4276 bc_parse_push(p, BC_INST_JUMP_ZERO);
4277 bc_parse_pushIndex(p, ip.idx);
4278 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4280 return BC_STATUS_SUCCESS;
4283 static BcStatus bc_parse_for(BcParse *p)
4287 size_t cond_idx, exit_idx, body_idx, update_idx;
4289 s = bc_lex_next(&p->l);
4291 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4292 s = bc_lex_next(&p->l);
4295 if (p->l.t.t != BC_LEX_SCOLON)
4296 s = bc_parse_expr(p, 0, bc_parse_next_for);
4298 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4301 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4302 s = bc_lex_next(&p->l);
4305 cond_idx = p->func->labels.len;
4306 update_idx = cond_idx + 1;
4307 body_idx = update_idx + 1;
4308 exit_idx = body_idx + 1;
4310 bc_vec_push(&p->func->labels, &p->func->code.len);
4312 if (p->l.t.t != BC_LEX_SCOLON)
4313 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4315 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4318 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4320 s = bc_lex_next(&p->l);
4323 bc_parse_push(p, BC_INST_JUMP_ZERO);
4324 bc_parse_pushIndex(p, exit_idx);
4325 bc_parse_push(p, BC_INST_JUMP);
4326 bc_parse_pushIndex(p, body_idx);
4328 ip.idx = p->func->labels.len;
4330 bc_vec_push(&p->conds, &update_idx);
4331 bc_vec_push(&p->func->labels, &p->func->code.len);
4333 if (p->l.t.t != BC_LEX_RPAREN)
4334 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4336 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4340 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4341 bc_parse_push(p, BC_INST_JUMP);
4342 bc_parse_pushIndex(p, cond_idx);
4343 bc_vec_push(&p->func->labels, &p->func->code.len);
4349 bc_vec_push(&p->exits, &ip);
4350 bc_vec_push(&p->func->labels, &ip.idx);
4352 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4354 return BC_STATUS_SUCCESS;
4357 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4363 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4365 if (type == BC_LEX_KEY_BREAK) {
4367 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4369 i = p->exits.len - 1;
4370 ip = bc_vec_item(&p->exits, i);
4372 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4373 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4378 i = *((size_t *) bc_vec_top(&p->conds));
4380 bc_parse_push(p, BC_INST_JUMP);
4381 bc_parse_pushIndex(p, i);
4383 s = bc_lex_next(&p->l);
4386 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4387 return BC_STATUS_PARSE_BAD_TOKEN;
4389 return bc_lex_next(&p->l);
4392 static BcStatus bc_parse_func(BcParse *p)
4395 bool var, comma = false;
4399 s = bc_lex_next(&p->l);
4401 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4403 name = xstrdup(p->l.t.v.v);
4404 bc_parse_addFunc(p, name, &p->fidx);
4406 s = bc_lex_next(&p->l);
4408 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4409 s = bc_lex_next(&p->l);
4412 while (p->l.t.t != BC_LEX_RPAREN) {
4414 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4418 name = xstrdup(p->l.t.v.v);
4419 s = bc_lex_next(&p->l);
4422 var = p->l.t.t != BC_LEX_LBRACKET;
4426 s = bc_lex_next(&p->l);
4429 if (p->l.t.t != BC_LEX_RBRACKET) {
4430 s = BC_STATUS_PARSE_BAD_FUNC;
4434 s = bc_lex_next(&p->l);
4438 comma = p->l.t.t == BC_LEX_COMMA;
4440 s = bc_lex_next(&p->l);
4444 s = bc_func_insert(p->func, name, var);
4448 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4450 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4451 bc_parse_startBody(p, flags);
4453 s = bc_lex_next(&p->l);
4456 if (p->l.t.t != BC_LEX_LBRACE)
4457 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4466 static BcStatus bc_parse_auto(BcParse *p)
4469 bool comma, var, one;
4472 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4473 s = bc_lex_next(&p->l);
4476 p->auto_part = comma = false;
4477 one = p->l.t.t == BC_LEX_NAME;
4479 while (p->l.t.t == BC_LEX_NAME) {
4481 name = xstrdup(p->l.t.v.v);
4482 s = bc_lex_next(&p->l);
4485 var = p->l.t.t != BC_LEX_LBRACKET;
4488 s = bc_lex_next(&p->l);
4491 if (p->l.t.t != BC_LEX_RBRACKET) {
4492 s = BC_STATUS_PARSE_BAD_FUNC;
4496 s = bc_lex_next(&p->l);
4500 comma = p->l.t.t == BC_LEX_COMMA;
4502 s = bc_lex_next(&p->l);
4506 s = bc_func_insert(p->func, name, var);
4510 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4511 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4513 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4514 return BC_STATUS_PARSE_BAD_TOKEN;
4516 return bc_lex_next(&p->l);
4523 static BcStatus bc_parse_body(BcParse *p, bool brace)
4525 BcStatus s = BC_STATUS_SUCCESS;
4526 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4528 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4530 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4532 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4533 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4535 if (!p->auto_part) {
4536 s = bc_parse_auto(p);
4540 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4543 s = bc_parse_stmt(p);
4544 if (!s && !brace) s = bc_parse_endBody(p, false);
4550 static BcStatus bc_parse_stmt(BcParse *p)
4552 BcStatus s = BC_STATUS_SUCCESS;
4558 return bc_lex_next(&p->l);
4561 case BC_LEX_KEY_ELSE:
4563 p->auto_part = false;
4569 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4572 s = bc_lex_next(&p->l);
4575 return bc_parse_body(p, true);
4578 case BC_LEX_KEY_AUTO:
4580 return bc_parse_auto(p);
4585 p->auto_part = false;
4587 if (BC_PARSE_IF_END(p)) {
4589 return BC_STATUS_SUCCESS;
4591 else if (BC_PARSE_BODY(p))
4592 return bc_parse_body(p, false);
4602 case BC_LEX_OP_MINUS:
4603 case BC_LEX_OP_BOOL_NOT:
4607 case BC_LEX_KEY_IBASE:
4608 case BC_LEX_KEY_LAST:
4609 case BC_LEX_KEY_LENGTH:
4610 case BC_LEX_KEY_OBASE:
4611 case BC_LEX_KEY_READ:
4612 case BC_LEX_KEY_SCALE:
4613 case BC_LEX_KEY_SQRT:
4615 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4619 case BC_LEX_KEY_ELSE:
4621 s = bc_parse_else(p);
4627 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4633 s = bc_parse_endBody(p, true);
4639 s = bc_parse_string(p, BC_INST_PRINT_STR);
4643 case BC_LEX_KEY_BREAK:
4644 case BC_LEX_KEY_CONTINUE:
4646 s = bc_parse_loopExit(p, p->l.t.t);
4650 case BC_LEX_KEY_FOR:
4652 s = bc_parse_for(p);
4656 case BC_LEX_KEY_HALT:
4658 bc_parse_push(p, BC_INST_HALT);
4659 s = bc_lex_next(&p->l);
4669 case BC_LEX_KEY_LIMITS:
4671 // "limits" is a compile-time command,
4672 // the output is produced at _parse time_.
4673 s = bc_lex_next(&p->l);
4675 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4676 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4677 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4678 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4679 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4680 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4681 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4682 printf("Number of vars = %lu\n", BC_MAX_VARS);
4686 case BC_LEX_KEY_PRINT:
4688 s = bc_parse_print(p);
4692 case BC_LEX_KEY_QUIT:
4694 // "quit" is a compile-time command. For example,
4695 // "if (0 == 1) quit" terminates when parsing the statement,
4696 // not when it is executed
4700 case BC_LEX_KEY_RETURN:
4702 s = bc_parse_return(p);
4706 case BC_LEX_KEY_WHILE:
4708 s = bc_parse_while(p);
4714 s = BC_STATUS_PARSE_BAD_TOKEN;
4722 static BcStatus bc_parse_parse(BcParse *p)
4726 if (p->l.t.t == BC_LEX_EOF)
4727 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4728 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4729 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4730 s = bc_parse_func(p);
4733 s = bc_parse_stmt(p);
4735 if (s || G_interrupt)
4736 s = bc_parse_reset(p, s);
4741 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4743 BcStatus s = BC_STATUS_SUCCESS;
4744 BcInst prev = BC_INST_PRINT;
4745 BcLexType top, t = p->l.t.t;
4746 size_t nexprs = 0, ops_bgn = p->ops.len;
4747 uint32_t i, nparens, nrelops;
4748 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4750 paren_first = p->l.t.t == BC_LEX_LPAREN;
4751 nparens = nrelops = 0;
4752 paren_expr = rprn = done = get_token = assign = false;
4755 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4761 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4762 rprn = get_token = bin_last = false;
4766 case BC_LEX_OP_MINUS:
4768 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4769 rprn = get_token = false;
4770 bin_last = prev == BC_INST_MINUS;
4774 case BC_LEX_OP_ASSIGN_POWER:
4775 case BC_LEX_OP_ASSIGN_MULTIPLY:
4776 case BC_LEX_OP_ASSIGN_DIVIDE:
4777 case BC_LEX_OP_ASSIGN_MODULUS:
4778 case BC_LEX_OP_ASSIGN_PLUS:
4779 case BC_LEX_OP_ASSIGN_MINUS:
4780 case BC_LEX_OP_ASSIGN:
4782 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4783 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4784 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4786 s = BC_STATUS_PARSE_BAD_ASSIGN;
4791 case BC_LEX_OP_POWER:
4792 case BC_LEX_OP_MULTIPLY:
4793 case BC_LEX_OP_DIVIDE:
4794 case BC_LEX_OP_MODULUS:
4795 case BC_LEX_OP_PLUS:
4796 case BC_LEX_OP_REL_EQ:
4797 case BC_LEX_OP_REL_LE:
4798 case BC_LEX_OP_REL_GE:
4799 case BC_LEX_OP_REL_NE:
4800 case BC_LEX_OP_REL_LT:
4801 case BC_LEX_OP_REL_GT:
4802 case BC_LEX_OP_BOOL_NOT:
4803 case BC_LEX_OP_BOOL_OR:
4804 case BC_LEX_OP_BOOL_AND:
4806 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4807 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4809 return BC_STATUS_PARSE_BAD_EXP;
4812 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4813 prev = BC_PARSE_TOKEN_INST(t);
4814 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4815 rprn = get_token = false;
4816 bin_last = t != BC_LEX_OP_BOOL_NOT;
4823 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4826 paren_expr = rprn = bin_last = false;
4828 bc_vec_push(&p->ops, &t);
4835 if (bin_last || prev == BC_INST_BOOL_NOT)
4836 return BC_STATUS_PARSE_BAD_EXP;
4839 s = BC_STATUS_SUCCESS;
4844 else if (!paren_expr)
4845 return BC_STATUS_PARSE_EMPTY_EXP;
4848 paren_expr = rprn = true;
4849 get_token = bin_last = false;
4851 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4858 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4861 rprn = get_token = bin_last = false;
4862 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4870 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4872 bc_parse_number(p, &prev, &nexprs);
4873 paren_expr = get_token = true;
4874 rprn = bin_last = false;
4879 case BC_LEX_KEY_IBASE:
4880 case BC_LEX_KEY_LAST:
4881 case BC_LEX_KEY_OBASE:
4883 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4885 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4886 bc_parse_push(p, (char) prev);
4888 paren_expr = get_token = true;
4889 rprn = bin_last = false;
4895 case BC_LEX_KEY_LENGTH:
4896 case BC_LEX_KEY_SQRT:
4898 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4900 s = bc_parse_builtin(p, t, flags, &prev);
4902 rprn = get_token = bin_last = false;
4908 case BC_LEX_KEY_READ:
4910 if (BC_PARSE_LEAF(prev, rprn))
4911 return BC_STATUS_PARSE_BAD_EXP;
4912 else if (flags & BC_PARSE_NOREAD)
4913 s = BC_STATUS_EXEC_REC_READ;
4915 s = bc_parse_read(p);
4918 rprn = get_token = bin_last = false;
4920 prev = BC_INST_READ;
4925 case BC_LEX_KEY_SCALE:
4927 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4929 s = bc_parse_scale(p, &prev, flags);
4931 rprn = get_token = bin_last = false;
4933 prev = BC_INST_SCALE;
4940 s = BC_STATUS_PARSE_BAD_TOKEN;
4945 if (!s && get_token) s = bc_lex_next(&p->l);
4949 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4951 while (p->ops.len > ops_bgn) {
4953 top = BC_PARSE_TOP_OP(p);
4954 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4956 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4957 return BC_STATUS_PARSE_BAD_EXP;
4959 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4961 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4962 bc_vec_pop(&p->ops);
4965 s = BC_STATUS_PARSE_BAD_EXP;
4966 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4968 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4971 if (!(flags & BC_PARSE_REL) && nrelops) {
4972 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4975 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4976 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4980 if (flags & BC_PARSE_PRINT) {
4981 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4982 bc_parse_push(p, BC_INST_POP);
4988 static void bc_parse_init(BcParse *p, size_t func)
4990 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4993 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4995 return bc_parse_expr(p, flags, bc_parse_next_read);
5000 static BcStatus dc_parse_register(BcParse *p)
5005 s = bc_lex_next(&p->l);
5007 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5009 name = xstrdup(p->l.t.v.v);
5010 bc_parse_pushName(p, name);
5015 static BcStatus dc_parse_string(BcParse *p)
5017 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5018 size_t idx, len = G.prog.strs.len;
5020 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5023 str = xstrdup(p->l.t.v.v);
5024 bc_parse_push(p, BC_INST_STR);
5025 bc_parse_pushIndex(p, len);
5026 bc_vec_push(&G.prog.strs, &str);
5027 bc_parse_addFunc(p, name, &idx);
5029 return bc_lex_next(&p->l);
5032 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5036 bc_parse_push(p, inst);
5038 s = dc_parse_register(p);
5043 bc_parse_push(p, BC_INST_SWAP);
5044 bc_parse_push(p, BC_INST_ASSIGN);
5045 bc_parse_push(p, BC_INST_POP);
5048 return bc_lex_next(&p->l);
5051 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5055 bc_parse_push(p, inst);
5056 bc_parse_push(p, BC_INST_EXEC_COND);
5058 s = dc_parse_register(p);
5061 s = bc_lex_next(&p->l);
5064 if (p->l.t.t == BC_LEX_ELSE) {
5065 s = dc_parse_register(p);
5067 s = bc_lex_next(&p->l);
5070 bc_parse_push(p, BC_PARSE_STREND);
5075 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5077 BcStatus s = BC_STATUS_SUCCESS;
5080 bool assign, get_token = false;
5084 case BC_LEX_OP_REL_EQ:
5085 case BC_LEX_OP_REL_LE:
5086 case BC_LEX_OP_REL_GE:
5087 case BC_LEX_OP_REL_NE:
5088 case BC_LEX_OP_REL_LT:
5089 case BC_LEX_OP_REL_GT:
5091 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5098 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5104 s = dc_parse_string(p);
5111 if (t == BC_LEX_NEG) {
5112 s = bc_lex_next(&p->l);
5114 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5117 bc_parse_number(p, &prev, &p->nbraces);
5119 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5125 case BC_LEX_KEY_READ:
5127 if (flags & BC_PARSE_NOREAD)
5128 s = BC_STATUS_EXEC_REC_READ;
5130 bc_parse_push(p, BC_INST_READ);
5135 case BC_LEX_OP_ASSIGN:
5136 case BC_LEX_STORE_PUSH:
5138 assign = t == BC_LEX_OP_ASSIGN;
5139 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5140 s = dc_parse_mem(p, inst, true, assign);
5145 case BC_LEX_LOAD_POP:
5147 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5148 s = dc_parse_mem(p, inst, true, false);
5152 case BC_LEX_STORE_IBASE:
5153 case BC_LEX_STORE_SCALE:
5154 case BC_LEX_STORE_OBASE:
5156 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5157 s = dc_parse_mem(p, inst, false, true);
5163 s = BC_STATUS_PARSE_BAD_TOKEN;
5169 if (!s && get_token) s = bc_lex_next(&p->l);
5174 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5176 BcStatus s = BC_STATUS_SUCCESS;
5180 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5182 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5184 inst = dc_parse_insts[t];
5186 if (inst != BC_INST_INVALID) {
5187 bc_parse_push(p, inst);
5188 s = bc_lex_next(&p->l);
5191 s = dc_parse_token(p, t, flags);
5194 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5195 bc_parse_push(p, BC_INST_POP_EXEC);
5200 static BcStatus dc_parse_parse(BcParse *p)
5204 if (p->l.t.t == BC_LEX_EOF)
5205 s = BC_STATUS_LEX_EOF;
5207 s = dc_parse_expr(p, 0);
5209 if (s || G_interrupt) s = bc_parse_reset(p, s);
5214 static void dc_parse_init(BcParse *p, size_t func)
5216 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5220 static void common_parse_init(BcParse *p, size_t func)
5223 bc_parse_init(p, func);
5225 dc_parse_init(p, func);
5229 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5232 return bc_parse_expression(p, flags);
5234 return dc_parse_expr(p, flags);
5238 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 s = bc_map_insert(map, &e, &i);
5253 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5256 bc_array_init(&data.v, var);
5257 bc_vec_push(v, &data.v);
5260 ptr = bc_vec_item(map, i);
5261 if (new) ptr->name = xstrdup(e.name);
5262 return bc_vec_item(v, ptr->idx);
5265 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5267 BcStatus s = BC_STATUS_SUCCESS;
5272 case BC_RESULT_TEMP:
5273 case BC_RESULT_IBASE:
5274 case BC_RESULT_SCALE:
5275 case BC_RESULT_OBASE:
5281 case BC_RESULT_CONSTANT:
5283 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5284 size_t base_t, len = strlen(*str);
5287 bc_num_init(&r->d.n, len);
5289 hex = hex && len == 1;
5290 base = hex ? &G.prog.hexb : &G.prog.ib;
5291 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5292 s = bc_num_parse(&r->d.n, *str, base, base_t);
5295 bc_num_free(&r->d.n);
5300 r->t = BC_RESULT_TEMP;
5306 case BC_RESULT_ARRAY:
5307 case BC_RESULT_ARRAY_ELEM:
5311 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5313 if (r->t == BC_RESULT_ARRAY_ELEM) {
5315 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5316 *num = bc_vec_item(v, r->d.id.idx);
5319 *num = bc_vec_top(v);
5324 case BC_RESULT_LAST:
5326 *num = &G.prog.last;
5340 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5341 BcResult **r, BcNum **rn, bool assign)
5345 BcResultType lt, rt;
5347 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5349 *r = bc_vec_item_rev(&G.prog.results, 0);
5350 *l = bc_vec_item_rev(&G.prog.results, 1);
5354 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5356 s = bc_program_num(*l, ln, false);
5358 s = bc_program_num(*r, rn, hex);
5361 // We run this again under these conditions in case any vector has been
5362 // reallocated out from under the BcNums or arrays we had.
5363 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5364 s = bc_program_num(*l, ln, false);
5368 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5369 return BC_STATUS_EXEC_BAD_TYPE;
5370 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5375 static void bc_program_binOpRetire(BcResult *r)
5377 r->t = BC_RESULT_TEMP;
5378 bc_vec_pop(&G.prog.results);
5379 bc_vec_pop(&G.prog.results);
5380 bc_vec_push(&G.prog.results, r);
5383 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5387 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5388 *r = bc_vec_top(&G.prog.results);
5390 s = bc_program_num(*r, n, false);
5393 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5398 static void bc_program_retire(BcResult *r, BcResultType t)
5401 bc_vec_pop(&G.prog.results);
5402 bc_vec_push(&G.prog.results, r);
5405 static BcStatus bc_program_op(char inst)
5408 BcResult *opd1, *opd2, res;
5409 BcNum *n1, *n2 = NULL;
5411 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5413 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5415 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5417 bc_program_binOpRetire(&res);
5422 bc_num_free(&res.d.n);
5426 static BcStatus bc_program_read(void)
5433 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5435 for (i = 0; i < G.prog.stack.len; ++i) {
5436 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5437 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5440 bc_vec_npop(&f->code, f->code.len);
5441 bc_vec_init(&buf, sizeof(char), NULL);
5443 s = bc_read_line(&buf, "read> ");
5446 common_parse_init(&parse, BC_PROG_READ);
5447 bc_lex_file(&parse.l, bc_program_stdin_name);
5449 s = bc_parse_text(&parse, buf.v);
5450 if (s) goto exec_err;
5451 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5452 if (s) goto exec_err;
5454 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5455 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5459 ip.func = BC_PROG_READ;
5461 ip.len = G.prog.results.len;
5463 // Update this pointer, just in case.
5464 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5466 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5467 bc_vec_push(&G.prog.stack, &ip);
5470 bc_parse_free(&parse);
5476 static size_t bc_program_index(char *code, size_t *bgn)
5478 char amt = code[(*bgn)++], i = 0;
5481 for (; i < amt; ++i, ++(*bgn))
5482 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5487 static char *bc_program_name(char *code, size_t *bgn)
5490 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5492 s = xmalloc(ptr - str + 1);
5495 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5503 static void bc_program_printString(const char *str, size_t *nchars)
5505 size_t i, len = strlen(str);
5514 for (i = 0; i < len; ++i, ++(*nchars)) {
5518 if (c != '\\' || i == len - 1)
5578 // Just print the backslash and following character.
5589 static BcStatus bc_program_print(char inst, size_t idx)
5591 BcStatus s = BC_STATUS_SUCCESS;
5596 bool pop = inst != BC_INST_PRINT;
5598 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5600 r = bc_vec_item_rev(&G.prog.results, idx);
5601 s = bc_program_num(r, &num, false);
5604 if (BC_PROG_NUM(r, num)) {
5605 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5606 if (!s) bc_num_copy(&G.prog.last, num);
5610 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5611 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5613 if (inst == BC_INST_PRINT_STR) {
5614 for (i = 0, len = strlen(str); i < len; ++i) {
5617 if (c == '\n') G.prog.nchars = SIZE_MAX;
5622 bc_program_printString(str, &G.prog.nchars);
5623 if (inst == BC_INST_PRINT) bb_putchar('\n');
5627 if (!s && pop) bc_vec_pop(&G.prog.results);
5632 static BcStatus bc_program_negate(void)
5638 s = bc_program_prep(&ptr, &num);
5641 bc_num_init(&res.d.n, num->len);
5642 bc_num_copy(&res.d.n, num);
5643 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5645 bc_program_retire(&res, BC_RESULT_TEMP);
5650 static BcStatus bc_program_logical(char inst)
5653 BcResult *opd1, *opd2, res;
5658 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5660 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5662 if (inst == BC_INST_BOOL_AND)
5663 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5664 else if (inst == BC_INST_BOOL_OR)
5665 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5668 cmp = bc_num_cmp(n1, n2);
5672 case BC_INST_REL_EQ:
5678 case BC_INST_REL_LE:
5684 case BC_INST_REL_GE:
5690 case BC_INST_REL_NE:
5696 case BC_INST_REL_LT:
5702 case BC_INST_REL_GT:
5710 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5712 bc_program_binOpRetire(&res);
5718 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5724 memset(&n2, 0, sizeof(BcNum));
5725 n2.rdx = res.d.id.idx = r->d.id.idx;
5726 res.t = BC_RESULT_STR;
5729 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5731 bc_vec_pop(&G.prog.results);
5734 bc_vec_pop(&G.prog.results);
5736 bc_vec_push(&G.prog.results, &res);
5737 bc_vec_push(v, &n2);
5739 return BC_STATUS_SUCCESS;
5743 static BcStatus bc_program_copyToVar(char *name, bool var)
5750 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5752 ptr = bc_vec_top(&G.prog.results);
5753 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5754 v = bc_program_search(name, var);
5757 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5758 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5761 s = bc_program_num(ptr, &n, false);
5764 // Do this once more to make sure that pointers were not invalidated.
5765 v = bc_program_search(name, var);
5768 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5769 bc_num_copy(&r.d.n, n);
5772 bc_array_init(&r.d.v, true);
5773 bc_array_copy(&r.d.v, (BcVec *) n);
5776 bc_vec_push(v, &r.d);
5777 bc_vec_pop(&G.prog.results);
5782 static BcStatus bc_program_assign(char inst)
5785 BcResult *left, *right, res;
5786 BcNum *l = NULL, *r = NULL;
5787 unsigned long val, max;
5788 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5790 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5793 ib = left->t == BC_RESULT_IBASE;
5794 sc = left->t == BC_RESULT_SCALE;
5798 if (right->t == BC_RESULT_STR) {
5802 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5803 v = bc_program_search(left->d.id.name, true);
5805 return bc_program_assignStr(right, v, false);
5809 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5810 return BC_STATUS_PARSE_BAD_ASSIGN;
5813 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5814 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5819 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5826 if (ib || sc || left->t == BC_RESULT_OBASE) {
5830 s = bc_num_ulong(l, &val);
5832 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5836 ptr = &G.prog.scale;
5839 if (val < BC_NUM_MIN_BASE) return s;
5840 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5841 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5844 if (val > max) return s;
5845 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5847 *ptr = (size_t) val;
5848 s = BC_STATUS_SUCCESS;
5851 bc_num_init(&res.d.n, l->len);
5852 bc_num_copy(&res.d.n, l);
5853 bc_program_binOpRetire(&res);
5859 #define bc_program_pushVar(code, bgn, pop, copy) \
5860 bc_program_pushVar(code, bgn)
5861 // for bc, 'pop' and 'copy' are always false
5863 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5864 bool pop, bool copy)
5866 BcStatus s = BC_STATUS_SUCCESS;
5868 char *name = bc_program_name(code, bgn);
5870 r.t = BC_RESULT_VAR;
5875 BcVec *v = bc_program_search(name, true);
5876 BcNum *num = bc_vec_top(v);
5880 if (!BC_PROG_STACK(v, 2 - copy)) {
5882 return BC_STATUS_EXEC_STACK;
5888 if (!BC_PROG_STR(num)) {
5890 r.t = BC_RESULT_TEMP;
5892 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5893 bc_num_copy(&r.d.n, num);
5896 r.t = BC_RESULT_STR;
5897 r.d.id.idx = num->rdx;
5900 if (!copy) bc_vec_pop(v);
5905 bc_vec_push(&G.prog.results, &r);
5910 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5913 BcStatus s = BC_STATUS_SUCCESS;
5917 r.d.id.name = bc_program_name(code, bgn);
5919 if (inst == BC_INST_ARRAY) {
5920 r.t = BC_RESULT_ARRAY;
5921 bc_vec_push(&G.prog.results, &r);
5928 s = bc_program_prep(&operand, &num);
5930 s = bc_num_ulong(num, &temp);
5933 if (temp > BC_MAX_DIM) {
5934 s = BC_STATUS_EXEC_ARRAY_LEN;
5938 r.d.id.idx = (size_t) temp;
5939 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5943 if (s) free(r.d.id.name);
5948 static BcStatus bc_program_incdec(char inst)
5951 BcResult *ptr, res, copy;
5955 s = bc_program_prep(&ptr, &num);
5958 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5959 copy.t = BC_RESULT_TEMP;
5960 bc_num_init(©.d.n, num->len);
5961 bc_num_copy(©.d.n, num);
5964 res.t = BC_RESULT_ONE;
5965 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5966 BC_INST_ASSIGN_PLUS :
5967 BC_INST_ASSIGN_MINUS;
5969 bc_vec_push(&G.prog.results, &res);
5970 bc_program_assign(inst);
5972 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5973 bc_vec_pop(&G.prog.results);
5974 bc_vec_push(&G.prog.results, ©);
5980 static BcStatus bc_program_call(char *code, size_t *idx)
5982 BcStatus s = BC_STATUS_SUCCESS;
5984 size_t i, nparams = bc_program_index(code, idx);
5991 ip.func = bc_program_index(code, idx);
5992 func = bc_vec_item(&G.prog.fns, ip.func);
5994 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
5995 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
5996 ip.len = G.prog.results.len - nparams;
5998 for (i = 0; i < nparams; ++i) {
6000 a = bc_vec_item(&func->autos, nparams - 1 - i);
6001 arg = bc_vec_top(&G.prog.results);
6003 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6004 return BC_STATUS_EXEC_BAD_TYPE;
6006 s = bc_program_copyToVar(a->name, a->idx);
6010 for (; i < func->autos.len; ++i) {
6013 a = bc_vec_item(&func->autos, i);
6014 v = bc_program_search(a->name, a->idx);
6017 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6018 bc_vec_push(v, ¶m.n);
6021 bc_array_init(¶m.v, true);
6022 bc_vec_push(v, ¶m.v);
6026 bc_vec_push(&G.prog.stack, &ip);
6028 return BC_STATUS_SUCCESS;
6031 static BcStatus bc_program_return(char inst)
6037 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6039 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6040 return BC_STATUS_EXEC_STACK;
6042 f = bc_vec_item(&G.prog.fns, ip->func);
6043 res.t = BC_RESULT_TEMP;
6045 if (inst == BC_INST_RET) {
6048 BcResult *operand = bc_vec_top(&G.prog.results);
6050 s = bc_program_num(operand, &num, false);
6052 bc_num_init(&res.d.n, num->len);
6053 bc_num_copy(&res.d.n, num);
6056 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6057 bc_num_zero(&res.d.n);
6060 // We need to pop arguments as well, so this takes that into account.
6061 for (i = 0; i < f->autos.len; ++i) {
6064 BcId *a = bc_vec_item(&f->autos, i);
6066 v = bc_program_search(a->name, a->idx);
6070 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6071 bc_vec_push(&G.prog.results, &res);
6072 bc_vec_pop(&G.prog.stack);
6074 return BC_STATUS_SUCCESS;
6078 static unsigned long bc_program_scale(BcNum *n)
6080 return (unsigned long) n->rdx;
6083 static unsigned long bc_program_len(BcNum *n)
6085 unsigned long len = n->len;
6088 if (n->rdx != n->len) return len;
6089 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6094 static BcStatus bc_program_builtin(char inst)
6100 bool len = inst == BC_INST_LENGTH;
6102 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6103 opnd = bc_vec_top(&G.prog.results);
6105 s = bc_program_num(opnd, &num, false);
6109 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6112 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6114 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6116 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6117 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6121 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6124 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6126 str = bc_vec_item(&G.prog.strs, idx);
6127 bc_num_ulong2num(&res.d.n, strlen(*str));
6131 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6132 bc_num_ulong2num(&res.d.n, f(num));
6135 bc_program_retire(&res, BC_RESULT_TEMP);
6141 static BcStatus bc_program_divmod(void)
6144 BcResult *opd1, *opd2, res, res2;
6145 BcNum *n1, *n2 = NULL;
6147 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6150 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6151 bc_num_init(&res2.d.n, n2->len);
6153 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6156 bc_program_binOpRetire(&res2);
6157 res.t = BC_RESULT_TEMP;
6158 bc_vec_push(&G.prog.results, &res);
6163 bc_num_free(&res2.d.n);
6164 bc_num_free(&res.d.n);
6168 static BcStatus bc_program_modexp(void)
6171 BcResult *r1, *r2, *r3, res;
6172 BcNum *n1, *n2, *n3;
6174 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6175 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6178 r1 = bc_vec_item_rev(&G.prog.results, 2);
6179 s = bc_program_num(r1, &n1, false);
6181 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6183 // Make sure that the values have their pointers updated, if necessary.
6184 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6186 if (r1->t == r2->t) {
6187 s = bc_program_num(r2, &n2, false);
6191 if (r1->t == r3->t) {
6192 s = bc_program_num(r3, &n3, false);
6197 bc_num_init(&res.d.n, n3->len);
6198 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6201 bc_vec_pop(&G.prog.results);
6202 bc_program_binOpRetire(&res);
6207 bc_num_free(&res.d.n);
6211 static void bc_program_stackLen(void)
6214 size_t len = G.prog.results.len;
6216 res.t = BC_RESULT_TEMP;
6218 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6219 bc_num_ulong2num(&res.d.n, len);
6220 bc_vec_push(&G.prog.results, &res);
6223 static BcStatus bc_program_asciify(void)
6227 BcNum *num = NULL, n;
6228 char *str, *str2, c;
6229 size_t len = G.prog.strs.len, idx;
6232 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6233 r = bc_vec_top(&G.prog.results);
6235 s = bc_program_num(r, &num, false);
6238 if (BC_PROG_NUM(r, num)) {
6240 bc_num_init(&n, BC_NUM_DEF_SIZE);
6241 bc_num_copy(&n, num);
6242 bc_num_truncate(&n, n.rdx);
6244 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6245 if (s) goto num_err;
6246 s = bc_num_ulong(&n, &val);
6247 if (s) goto num_err;
6254 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6255 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6263 str2 = xstrdup(str);
6264 bc_program_addFunc(str2, &idx);
6266 if (idx != len + BC_PROG_REQ_FUNCS) {
6268 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6269 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6278 bc_vec_push(&G.prog.strs, &str);
6280 res.t = BC_RESULT_STR;
6282 bc_vec_pop(&G.prog.results);
6283 bc_vec_push(&G.prog.results, &res);
6285 return BC_STATUS_SUCCESS;
6292 static BcStatus bc_program_printStream(void)
6300 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6301 r = bc_vec_top(&G.prog.results);
6303 s = bc_program_num(r, &n, false);
6306 if (BC_PROG_NUM(r, n))
6307 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6309 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6310 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6317 static BcStatus bc_program_nquit(void)
6324 s = bc_program_prep(&opnd, &num);
6326 s = bc_num_ulong(num, &val);
6329 bc_vec_pop(&G.prog.results);
6331 if (G.prog.stack.len < val)
6332 return BC_STATUS_EXEC_STACK;
6333 if (G.prog.stack.len == val)
6336 bc_vec_npop(&G.prog.stack, val);
6341 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6344 BcStatus s = BC_STATUS_SUCCESS;
6354 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6356 r = bc_vec_top(&G.prog.results);
6360 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6362 if (code[*bgn] == BC_PARSE_STREND)
6365 else_name = bc_program_name(code, bgn);
6367 exec = r->d.n.len != 0;
6371 else if (else_name != NULL) {
6378 v = bc_program_search(name, true);
6385 if (!exec) goto exit;
6386 if (!BC_PROG_STR(n)) {
6387 s = BC_STATUS_EXEC_BAD_TYPE;
6395 if (r->t == BC_RESULT_STR)
6397 else if (r->t == BC_RESULT_VAR) {
6398 s = bc_program_num(r, &n, false);
6399 if (s || !BC_PROG_STR(n)) goto exit;
6406 fidx = sidx + BC_PROG_REQ_FUNCS;
6408 str = bc_vec_item(&G.prog.strs, sidx);
6409 f = bc_vec_item(&G.prog.fns, fidx);
6411 if (f->code.len == 0) {
6412 common_parse_init(&prs, fidx);
6413 s = bc_parse_text(&prs, *str);
6415 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6418 if (prs.l.t.t != BC_LEX_EOF) {
6419 s = BC_STATUS_PARSE_BAD_EXP;
6423 bc_parse_free(&prs);
6427 ip.len = G.prog.results.len;
6430 bc_vec_pop(&G.prog.results);
6431 bc_vec_push(&G.prog.stack, &ip);
6433 return BC_STATUS_SUCCESS;
6436 bc_parse_free(&prs);
6437 f = bc_vec_item(&G.prog.fns, fidx);
6438 bc_vec_npop(&f->code, f->code.len);
6440 bc_vec_pop(&G.prog.results);
6445 static void bc_program_pushGlobal(char inst)
6450 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6451 if (inst == BC_INST_IBASE)
6452 val = (unsigned long) G.prog.ib_t;
6453 else if (inst == BC_INST_SCALE)
6454 val = (unsigned long) G.prog.scale;
6456 val = (unsigned long) G.prog.ob_t;
6458 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6459 bc_num_ulong2num(&res.d.n, val);
6460 bc_vec_push(&G.prog.results, &res);
6463 static void bc_program_addFunc(char *name, size_t *idx)
6466 BcId entry, *entry_ptr;
6470 entry.idx = G.prog.fns.len;
6472 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
6475 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6476 *idx = entry_ptr->idx;
6478 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6480 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6482 // We need to reset these, so the function can be repopulated.
6484 bc_vec_npop(&func->autos, func->autos.len);
6485 bc_vec_npop(&func->code, func->code.len);
6486 bc_vec_npop(&func->labels, func->labels.len);
6490 bc_vec_push(&G.prog.fns, &f);
6494 static BcStatus bc_program_reset(BcStatus s)
6499 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6500 bc_vec_npop(&G.prog.results, G.prog.results.len);
6502 f = bc_vec_item(&G.prog.fns, 0);
6503 ip = bc_vec_top(&G.prog.stack);
6504 ip->idx = f->code.len;
6506 if (!s && G_interrupt && !G.tty) quit();
6508 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6511 fflush_and_check(); // make sure buffered stdout is printed
6512 fputs(bc_program_ready_msg, stderr);
6514 s = BC_STATUS_SUCCESS;
6520 static BcStatus bc_program_exec(void)
6522 BcStatus s = BC_STATUS_SUCCESS;
6526 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6527 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6528 char *code = func->code.v;
6531 while (!s && ip->idx < func->code.len) {
6533 char inst = code[(ip->idx)++];
6538 case BC_INST_JUMP_ZERO:
6540 s = bc_program_prep(&ptr, &num);
6542 cond = !bc_num_cmp(num, &G.prog.zero);
6543 bc_vec_pop(&G.prog.results);
6549 idx = bc_program_index(code, &ip->idx);
6550 addr = bc_vec_item(&func->labels, idx);
6551 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6557 s = bc_program_call(code, &ip->idx);
6561 case BC_INST_INC_PRE:
6562 case BC_INST_DEC_PRE:
6563 case BC_INST_INC_POST:
6564 case BC_INST_DEC_POST:
6566 s = bc_program_incdec(inst);
6579 s = bc_program_return(inst);
6583 case BC_INST_BOOL_OR:
6584 case BC_INST_BOOL_AND:
6586 case BC_INST_REL_EQ:
6587 case BC_INST_REL_LE:
6588 case BC_INST_REL_GE:
6589 case BC_INST_REL_NE:
6590 case BC_INST_REL_LT:
6591 case BC_INST_REL_GT:
6593 s = bc_program_logical(inst);
6599 s = bc_program_read();
6605 s = bc_program_pushVar(code, &ip->idx, false, false);
6609 case BC_INST_ARRAY_ELEM:
6612 s = bc_program_pushArray(code, &ip->idx, inst);
6618 r.t = BC_RESULT_LAST;
6619 bc_vec_push(&G.prog.results, &r);
6627 bc_program_pushGlobal(inst);
6631 case BC_INST_SCALE_FUNC:
6632 case BC_INST_LENGTH:
6635 s = bc_program_builtin(inst);
6641 r.t = BC_RESULT_CONSTANT;
6642 r.d.id.idx = bc_program_index(code, &ip->idx);
6643 bc_vec_push(&G.prog.results, &r);
6649 if (!BC_PROG_STACK(&G.prog.results, 1))
6650 s = BC_STATUS_EXEC_STACK;
6652 bc_vec_pop(&G.prog.results);
6656 case BC_INST_POP_EXEC:
6658 bc_vec_pop(&G.prog.stack);
6663 case BC_INST_PRINT_POP:
6664 case BC_INST_PRINT_STR:
6666 s = bc_program_print(inst, 0);
6672 r.t = BC_RESULT_STR;
6673 r.d.id.idx = bc_program_index(code, &ip->idx);
6674 bc_vec_push(&G.prog.results, &r);
6679 case BC_INST_MULTIPLY:
6680 case BC_INST_DIVIDE:
6681 case BC_INST_MODULUS:
6685 s = bc_program_op(inst);
6689 case BC_INST_BOOL_NOT:
6691 s = bc_program_prep(&ptr, &num);
6694 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6695 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6696 bc_program_retire(&r, BC_RESULT_TEMP);
6703 s = bc_program_negate();
6708 case BC_INST_ASSIGN_POWER:
6709 case BC_INST_ASSIGN_MULTIPLY:
6710 case BC_INST_ASSIGN_DIVIDE:
6711 case BC_INST_ASSIGN_MODULUS:
6712 case BC_INST_ASSIGN_PLUS:
6713 case BC_INST_ASSIGN_MINUS:
6715 case BC_INST_ASSIGN:
6717 s = bc_program_assign(inst);
6721 case BC_INST_MODEXP:
6723 s = bc_program_modexp();
6727 case BC_INST_DIVMOD:
6729 s = bc_program_divmod();
6733 case BC_INST_EXECUTE:
6734 case BC_INST_EXEC_COND:
6736 cond = inst == BC_INST_EXEC_COND;
6737 s = bc_program_execStr(code, &ip->idx, cond);
6741 case BC_INST_PRINT_STACK:
6743 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6744 s = bc_program_print(BC_INST_PRINT, idx);
6748 case BC_INST_CLEAR_STACK:
6750 bc_vec_npop(&G.prog.results, G.prog.results.len);
6754 case BC_INST_STACK_LEN:
6756 bc_program_stackLen();
6760 case BC_INST_DUPLICATE:
6762 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6763 ptr = bc_vec_top(&G.prog.results);
6764 bc_result_copy(&r, ptr);
6765 bc_vec_push(&G.prog.results, &r);
6773 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6775 ptr = bc_vec_item_rev(&G.prog.results, 0);
6776 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6777 memcpy(&r, ptr, sizeof(BcResult));
6778 memcpy(ptr, ptr2, sizeof(BcResult));
6779 memcpy(ptr2, &r, sizeof(BcResult));
6784 case BC_INST_ASCIIFY:
6786 s = bc_program_asciify();
6790 case BC_INST_PRINT_STREAM:
6792 s = bc_program_printStream();
6797 case BC_INST_PUSH_VAR:
6799 bool copy = inst == BC_INST_LOAD;
6800 s = bc_program_pushVar(code, &ip->idx, true, copy);
6804 case BC_INST_PUSH_TO_VAR:
6806 char *name = bc_program_name(code, &ip->idx);
6807 s = bc_program_copyToVar(name, true);
6814 if (G.prog.stack.len <= 2)
6816 bc_vec_npop(&G.prog.stack, 2);
6822 s = bc_program_nquit();
6828 if (s || G_interrupt) s = bc_program_reset(s);
6830 // If the stack has changed, pointers may be invalid.
6831 ip = bc_vec_top(&G.prog.stack);
6832 func = bc_vec_item(&G.prog.fns, ip->func);
6833 code = func->code.v;
6839 static void bc_vm_info(void)
6841 printf("%s "BB_VER"\n"
6842 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6843 "Report bugs at: https://github.com/gavinhoward/bc\n"
6844 "This is free software with ABSOLUTELY NO WARRANTY\n"
6848 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6850 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6852 fprintf(stderr, bc_err_fmt, bc_err_msgs[s]);
6853 fprintf(stderr, " %s", file);
6854 fprintf(stderr, bc_err_line + 4 * !line, line);
6856 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6860 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6865 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W))) return BC_STATUS_SUCCESS;
6866 if (s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6868 fmt = G_posix ? bc_err_fmt : bc_warn_fmt;
6869 fprintf(stderr, fmt, bc_err_msgs[s]);
6870 if (msg) fprintf(stderr, " %s\n", msg);
6871 fprintf(stderr, " %s", file);
6872 fprintf(stderr, bc_err_line + 4 * !line, line);
6874 if (G.ttyin || !G_posix)
6875 s = BC_STATUS_SUCCESS;
6879 static void bc_vm_envArgs(void)
6881 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6884 char *env_args = getenv(bc_args_env_name), *buf;
6886 if (!env_args) return;
6888 G.env_args = xstrdup(env_args);
6891 bc_vec_init(&v, sizeof(char *), NULL);
6892 bc_vec_push(&v, &bc_args_env_name);
6895 if (!isspace(*buf)) {
6896 bc_vec_push(&v, &buf);
6897 while (*buf != 0 && !isspace(*buf)) ++buf;
6898 if (*buf != 0) (*(buf++)) = '\0';
6904 bc_args((int) v.len, (char **) v.v);
6910 static size_t bc_vm_envLen(const char *var)
6912 char *lenv = getenv(var);
6913 size_t i, len = BC_NUM_PRINT_WIDTH;
6916 if (!lenv) return len;
6920 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6922 len = (size_t) atoi(lenv) - 1;
6923 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6926 len = BC_NUM_PRINT_WIDTH;
6931 static BcStatus bc_vm_process(const char *text)
6933 BcStatus s = bc_parse_text(&G.prs, text);
6935 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6938 while (G.prs.l.t.t != BC_LEX_EOF) {
6940 s = G.prs.parse(&G.prs);
6942 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6946 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6947 s = bc_program_exec();
6950 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
6956 static BcStatus bc_vm_file(const char *file)
6964 data = bc_read_file(file);
6965 if (!data) return bc_error("file '%s' is not text", file);
6967 bc_lex_file(&G.prs.l, file);
6968 s = bc_vm_process(data);
6971 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6972 ip = bc_vec_item(&G.prog.stack, 0);
6974 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
6981 static BcStatus bc_vm_stdin(void)
6985 size_t len, i, str = 0;
6986 bool comment = false;
6988 G.prog.file = bc_program_stdin_name;
6989 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6991 bc_vec_init(&buffer, sizeof(char), NULL);
6992 bc_vec_init(&buf, sizeof(char), NULL);
6993 bc_vec_pushByte(&buffer, '\0');
6995 // This loop is complex because the vm tries not to send any lines that end
6996 // with a backslash to the parser. The reason for that is because the parser
6997 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6998 // case, and for strings and comments, the parser will expect more stuff.
6999 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7001 char *string = buf.v;
7006 if (str && buf.v[0] == G.send)
7008 else if (buf.v[0] == G.sbgn)
7011 else if (len > 1 || comment) {
7013 for (i = 0; i < len; ++i) {
7015 bool notend = len > i + 1;
7018 if (i - 1 > len || string[i - 1] != '\\') {
7019 if (G.sbgn == G.send)
7021 else if (c == G.send)
7023 else if (c == G.sbgn)
7027 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7031 else if (c == '*' && notend && comment && string[i + 1] == '/')
7035 if (str || comment || string[len - 2] == '\\') {
7036 bc_vec_concat(&buffer, buf.v);
7041 bc_vec_concat(&buffer, buf.v);
7042 s = bc_vm_process(buffer.v);
7045 bc_vec_npop(&buffer, buffer.len);
7049 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7052 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7057 bc_vec_free(&buffer);
7061 static BcStatus bc_vm_exec(void)
7063 BcStatus s = BC_STATUS_SUCCESS;
7067 if (G.flags & BC_FLAG_L) {
7069 bc_lex_file(&G.prs.l, bc_lib_name);
7070 s = bc_parse_text(&G.prs, bc_lib);
7072 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7075 s = bc_program_exec();
7080 for (i = 0; !s && i < G.files.len; ++i)
7081 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7084 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7085 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7090 #if ENABLE_FEATURE_CLEAN_UP
7091 static void bc_program_free()
7093 bc_num_free(&G.prog.ib);
7094 bc_num_free(&G.prog.ob);
7095 bc_num_free(&G.prog.hexb);
7097 bc_num_free(&G.prog.strmb);
7099 bc_vec_free(&G.prog.fns);
7100 bc_vec_free(&G.prog.fn_map);
7101 bc_vec_free(&G.prog.vars);
7102 bc_vec_free(&G.prog.var_map);
7103 bc_vec_free(&G.prog.arrs);
7104 bc_vec_free(&G.prog.arr_map);
7105 bc_vec_free(&G.prog.strs);
7106 bc_vec_free(&G.prog.consts);
7107 bc_vec_free(&G.prog.results);
7108 bc_vec_free(&G.prog.stack);
7109 bc_num_free(&G.prog.last);
7110 bc_num_free(&G.prog.zero);
7111 bc_num_free(&G.prog.one);
7114 static void bc_vm_free(void)
7116 bc_vec_free(&G.files);
7118 bc_parse_free(&G.prs);
7123 static void bc_program_init(size_t line_len)
7128 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7129 memset(&ip, 0, sizeof(BcInstPtr));
7131 /* G.prog.nchars = G.prog.scale = 0; - already is */
7132 G.prog.len = line_len;
7134 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7135 bc_num_ten(&G.prog.ib);
7138 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7139 bc_num_ten(&G.prog.ob);
7142 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7143 bc_num_ten(&G.prog.hexb);
7144 G.prog.hexb.num[0] = 6;
7147 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7148 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7151 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7152 bc_num_zero(&G.prog.last);
7154 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7155 bc_num_zero(&G.prog.zero);
7157 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7158 bc_num_one(&G.prog.one);
7160 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7161 bc_map_init(&G.prog.fn_map);
7163 bc_program_addFunc(xstrdup("(main)"), &idx);
7164 bc_program_addFunc(xstrdup("(read)"), &idx);
7166 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7167 bc_map_init(&G.prog.var_map);
7169 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7170 bc_map_init(&G.prog.arr_map);
7172 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7173 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7174 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7175 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7176 bc_vec_push(&G.prog.stack, &ip);
7179 static void bc_vm_init(const char *env_len)
7181 size_t len = bc_vm_envLen(env_len);
7183 #if ENABLE_FEATURE_BC_SIGNALS
7184 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7187 bc_vec_init(&G.files, sizeof(char *), NULL);
7190 if (getenv("POSIXLY_CORRECT"))
7191 G.flags |= BC_FLAG_S;
7195 bc_program_init(len);
7197 bc_parse_init(&G.prs, BC_PROG_MAIN);
7199 dc_parse_init(&G.prs, BC_PROG_MAIN);
7203 static BcStatus bc_vm_run(int argc, char *argv[],
7204 const char *env_len)
7208 bc_vm_init(env_len);
7209 bc_args(argc, argv);
7211 G.ttyin = isatty(0);
7212 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7214 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7217 #if ENABLE_FEATURE_CLEAN_UP
7224 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7225 int bc_main(int argc, char **argv)
7228 G.sbgn = G.send = '"';
7230 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7235 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7236 int dc_main(int argc, char **argv)
7242 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");