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;
3094 l->t.t = BC_LEX_WHITESPACE;
3107 return BC_STATUS_LEX_NO_COMMENT_END;
3116 return BC_STATUS_SUCCESS;
3119 static BcStatus bc_lex_token(BcLex *l)
3121 BcStatus s = BC_STATUS_SUCCESS;
3122 char c = l->buf[l->i++], c2;
3124 // This is the workhorse of the lexer.
3131 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3141 bc_lex_whitespace(l);
3147 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3149 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3150 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3159 s = bc_lex_string(l);
3165 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3168 bc_lex_lineComment(l);
3175 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3184 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3188 l->t.t = BC_LEX_OP_BOOL_AND;
3191 l->t.t = BC_LEX_INVALID;
3192 s = bc_error("bad character '%c'", '&');
3201 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3207 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3216 l->t.t = BC_LEX_OP_INC;
3219 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3225 l->t.t = BC_LEX_COMMA;
3234 l->t.t = BC_LEX_OP_DEC;
3237 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3243 if (isdigit(l->buf[l->i]))
3244 s = bc_lex_number(l, c);
3246 l->t.t = BC_LEX_KEY_LAST;
3247 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3256 s = bc_lex_comment(l);
3258 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3279 s = bc_lex_number(l, c);
3285 l->t.t = BC_LEX_SCOLON;
3291 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3297 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3303 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3310 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3316 if (l->buf[l->i] == '\n') {
3317 l->t.t = BC_LEX_WHITESPACE;
3321 s = bc_error("bad character '%c'", c);
3327 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3358 s = bc_lex_identifier(l);
3365 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3375 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3379 l->t.t = BC_LEX_OP_BOOL_OR;
3382 l->t.t = BC_LEX_INVALID;
3383 s = bc_error("bad character '%c'", c);
3391 l->t.t = BC_LEX_INVALID;
3392 s = bc_error("bad character '%c'", c);
3402 static BcStatus dc_lex_register(BcLex *l)
3404 BcStatus s = BC_STATUS_SUCCESS;
3406 if (isspace(l->buf[l->i - 1])) {
3407 bc_lex_whitespace(l);
3410 s = BC_STATUS_LEX_EXTENDED_REG;
3415 bc_vec_npop(&l->t.v, l->t.v.len);
3416 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3417 bc_vec_pushByte(&l->t.v, '\0');
3418 l->t.t = BC_LEX_NAME;
3424 static BcStatus dc_lex_string(BcLex *l)
3426 size_t depth = 1, nls = 0, i = l->i;
3429 l->t.t = BC_LEX_STR;
3430 bc_vec_npop(&l->t.v, l->t.v.len);
3432 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3434 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3435 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3438 if (depth) bc_vec_push(&l->t.v, &c);
3443 return BC_STATUS_LEX_NO_STRING_END;
3446 bc_vec_pushByte(&l->t.v, '\0');
3447 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3452 return BC_STATUS_SUCCESS;
3455 static BcStatus dc_lex_token(BcLex *l)
3457 BcStatus s = BC_STATUS_SUCCESS;
3458 char c = l->buf[l->i++], c2;
3461 for (i = 0; i < dc_lex_regs_len; ++i) {
3462 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3465 if (c >= '%' && c <= '~' &&
3466 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3471 // This is the workhorse of the lexer.
3476 l->t.t = BC_LEX_EOF;
3487 l->newline = (c == '\n');
3488 bc_lex_whitespace(l);
3497 l->t.t = BC_LEX_OP_REL_NE;
3499 l->t.t = BC_LEX_OP_REL_LE;
3501 l->t.t = BC_LEX_OP_REL_GE;
3503 return bc_error("bad character '%c'", c);
3511 bc_lex_lineComment(l);
3517 if (isdigit(l->buf[l->i]))
3518 s = bc_lex_number(l, c);
3520 s = bc_error("bad character '%c'", c);
3541 s = bc_lex_number(l, c);
3547 s = dc_lex_string(l);
3553 l->t.t = BC_LEX_INVALID;
3554 s = bc_error("bad character '%c'", c);
3563 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3565 bc_program_addFunc(name, idx);
3566 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3569 static void bc_parse_pushName(BcParse *p, char *name)
3571 size_t i = 0, len = strlen(name);
3573 for (; i < len; ++i) bc_parse_push(p, name[i]);
3574 bc_parse_push(p, BC_PARSE_STREND);
3579 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3581 unsigned char amt, i, nums[sizeof(size_t)];
3583 for (amt = 0; idx; ++amt) {
3584 nums[amt] = (char) idx;
3585 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3588 bc_parse_push(p, amt);
3589 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3592 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3594 char *num = xstrdup(p->l.t.v.v);
3595 size_t idx = G.prog.consts.len;
3597 bc_vec_push(&G.prog.consts, &num);
3599 bc_parse_push(p, BC_INST_NUM);
3600 bc_parse_pushIndex(p, idx);
3603 (*prev) = BC_INST_NUM;
3606 static BcStatus bc_parse_text(BcParse *p, const char *text)
3610 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3612 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3613 p->l.t.t = BC_LEX_INVALID;
3616 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3619 return bc_lex_text(&p->l, text);
3622 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3624 if (p->fidx != BC_PROG_MAIN) {
3626 p->func->nparams = 0;
3627 bc_vec_npop(&p->func->code, p->func->code.len);
3628 bc_vec_npop(&p->func->autos, p->func->autos.len);
3629 bc_vec_npop(&p->func->labels, p->func->labels.len);
3631 bc_parse_updateFunc(p, BC_PROG_MAIN);
3635 p->l.t.t = BC_LEX_EOF;
3636 p->auto_part = (p->nbraces = 0);
3638 bc_vec_npop(&p->flags, p->flags.len - 1);
3639 bc_vec_npop(&p->exits, p->exits.len);
3640 bc_vec_npop(&p->conds, p->conds.len);
3641 bc_vec_npop(&p->ops, p->ops.len);
3643 return bc_program_reset(s);
3646 static void bc_parse_free(BcParse *p)
3648 bc_vec_free(&p->flags);
3649 bc_vec_free(&p->exits);
3650 bc_vec_free(&p->conds);
3651 bc_vec_free(&p->ops);
3655 static void bc_parse_create(BcParse *p, size_t func,
3656 BcParseParse parse, BcLexNext next)
3658 memset(p, 0, sizeof(BcParse));
3660 bc_lex_init(&p->l, next);
3661 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3662 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3663 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3664 bc_vec_pushByte(&p->flags, 0);
3665 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3668 // p->auto_part = p->nbraces = 0; - already is
3669 bc_parse_updateFunc(p, func);
3673 static BcStatus bc_parse_else(BcParse *p);
3674 static BcStatus bc_parse_stmt(BcParse *p);
3676 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3677 size_t *nexprs, bool next)
3679 BcStatus s = BC_STATUS_SUCCESS;
3681 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3682 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3684 while (p->ops.len > start) {
3686 t = BC_PARSE_TOP_OP(p);
3687 if (t == BC_LEX_LPAREN) break;
3689 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3690 if (l >= r && (l != r || !left)) break;
3692 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3693 bc_vec_pop(&p->ops);
3694 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3697 bc_vec_push(&p->ops, &type);
3698 if (next) s = bc_lex_next(&p->l);
3703 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3707 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3708 top = BC_PARSE_TOP_OP(p);
3710 while (top != BC_LEX_LPAREN) {
3712 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3714 bc_vec_pop(&p->ops);
3715 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3717 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3718 top = BC_PARSE_TOP_OP(p);
3721 bc_vec_pop(&p->ops);
3723 return bc_lex_next(&p->l);
3726 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3732 s = bc_lex_next(&p->l);
3735 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3737 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3738 s = bc_parse_expr(p, flags, bc_parse_next_param);
3741 comma = p->l.t.t == BC_LEX_COMMA;
3743 s = bc_lex_next(&p->l);
3748 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3749 bc_parse_push(p, BC_INST_CALL);
3750 bc_parse_pushIndex(p, nparams);
3752 return BC_STATUS_SUCCESS;
3755 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3758 BcId entry, *entry_ptr;
3763 s = bc_parse_params(p, flags);
3766 if (p->l.t.t != BC_LEX_RPAREN) {
3767 s = BC_STATUS_PARSE_BAD_TOKEN;
3771 idx = bc_map_index(&G.prog.fn_map, &entry);
3773 if (idx == BC_VEC_INVALID_IDX) {
3774 name = xstrdup(entry.name);
3775 bc_parse_addFunc(p, name, &idx);
3776 idx = bc_map_index(&G.prog.fn_map, &entry);
3782 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3783 bc_parse_pushIndex(p, entry_ptr->idx);
3785 return bc_lex_next(&p->l);
3792 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3797 name = xstrdup(p->l.t.v.v);
3798 s = bc_lex_next(&p->l);
3801 if (p->l.t.t == BC_LEX_LBRACKET) {
3803 s = bc_lex_next(&p->l);
3806 if (p->l.t.t == BC_LEX_RBRACKET) {
3808 if (!(flags & BC_PARSE_ARRAY)) {
3809 s = BC_STATUS_PARSE_BAD_EXP;
3813 *type = BC_INST_ARRAY;
3817 *type = BC_INST_ARRAY_ELEM;
3819 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3820 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3824 s = bc_lex_next(&p->l);
3826 bc_parse_push(p, *type);
3827 bc_parse_pushName(p, name);
3829 else if (p->l.t.t == BC_LEX_LPAREN) {
3831 if (flags & BC_PARSE_NOCALL) {
3832 s = BC_STATUS_PARSE_BAD_TOKEN;
3836 *type = BC_INST_CALL;
3837 s = bc_parse_call(p, name, flags);
3840 *type = BC_INST_VAR;
3841 bc_parse_push(p, BC_INST_VAR);
3842 bc_parse_pushName(p, name);
3852 static BcStatus bc_parse_read(BcParse *p)
3856 s = bc_lex_next(&p->l);
3858 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3860 s = bc_lex_next(&p->l);
3862 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3864 bc_parse_push(p, BC_INST_READ);
3866 return bc_lex_next(&p->l);
3869 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3874 s = bc_lex_next(&p->l);
3876 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3878 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3880 s = bc_lex_next(&p->l);
3883 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3886 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3888 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3889 bc_parse_push(p, *prev);
3891 return bc_lex_next(&p->l);
3894 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3898 s = bc_lex_next(&p->l);
3901 if (p->l.t.t != BC_LEX_LPAREN) {
3902 *type = BC_INST_SCALE;
3903 bc_parse_push(p, BC_INST_SCALE);
3904 return BC_STATUS_SUCCESS;
3907 *type = BC_INST_SCALE_FUNC;
3908 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3910 s = bc_lex_next(&p->l);
3913 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3915 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3916 bc_parse_push(p, BC_INST_SCALE_FUNC);
3918 return bc_lex_next(&p->l);
3921 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3922 size_t *nexprs, uint8_t flags)
3927 BcInst etype = *prev;
3929 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3930 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3931 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3933 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3934 bc_parse_push(p, inst);
3935 s = bc_lex_next(&p->l);
3939 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3942 s = bc_lex_next(&p->l);
3946 // Because we parse the next part of the expression
3947 // right here, we need to increment this.
3948 *nexprs = *nexprs + 1;
3954 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3958 case BC_LEX_KEY_IBASE:
3959 case BC_LEX_KEY_LAST:
3960 case BC_LEX_KEY_OBASE:
3962 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3963 s = bc_lex_next(&p->l);
3967 case BC_LEX_KEY_SCALE:
3969 s = bc_lex_next(&p->l);
3971 if (p->l.t.t == BC_LEX_LPAREN)
3972 s = BC_STATUS_PARSE_BAD_TOKEN;
3974 bc_parse_push(p, BC_INST_SCALE);
3980 s = BC_STATUS_PARSE_BAD_TOKEN;
3985 if (!s) bc_parse_push(p, inst);
3991 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3992 bool rparen, size_t *nexprs)
3996 BcInst etype = *prev;
3998 s = bc_lex_next(&p->l);
4001 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4002 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4005 *prev = BC_PARSE_TOKEN_INST(type);
4007 // We can just push onto the op stack because this is the largest
4008 // precedence operator that gets pushed. Inc/dec does not.
4009 if (type != BC_LEX_OP_MINUS)
4010 bc_vec_push(&p->ops, &type);
4012 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4017 static BcStatus bc_parse_string(BcParse *p, char inst)
4019 char *str = xstrdup(p->l.t.v.v);
4021 bc_parse_push(p, BC_INST_STR);
4022 bc_parse_pushIndex(p, G.prog.strs.len);
4023 bc_vec_push(&G.prog.strs, &str);
4024 bc_parse_push(p, inst);
4026 return bc_lex_next(&p->l);
4029 static BcStatus bc_parse_print(BcParse *p)
4035 s = bc_lex_next(&p->l);
4040 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4041 return BC_STATUS_PARSE_BAD_PRINT;
4043 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4045 if (type == BC_LEX_STR)
4046 s = bc_parse_string(p, BC_INST_PRINT_POP);
4048 s = bc_parse_expr(p, 0, bc_parse_next_print);
4050 bc_parse_push(p, BC_INST_PRINT_POP);
4055 comma = p->l.t.t == BC_LEX_COMMA;
4056 if (comma) s = bc_lex_next(&p->l);
4061 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4063 return bc_lex_next(&p->l);
4066 static BcStatus bc_parse_return(BcParse *p)
4072 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4074 s = bc_lex_next(&p->l);
4078 paren = t == BC_LEX_LPAREN;
4080 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4081 bc_parse_push(p, BC_INST_RET0);
4084 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4085 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4087 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4088 bc_parse_push(p, BC_INST_RET0);
4089 s = bc_lex_next(&p->l);
4093 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4094 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4098 bc_parse_push(p, BC_INST_RET);
4104 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4106 BcStatus s = BC_STATUS_SUCCESS;
4108 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4109 return BC_STATUS_PARSE_BAD_TOKEN;
4113 if (p->l.t.t == BC_LEX_RBRACE) {
4114 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4116 s = bc_lex_next(&p->l);
4120 return BC_STATUS_PARSE_BAD_TOKEN;
4123 if (BC_PARSE_IF(p)) {
4127 while (p->l.t.t == BC_LEX_NLINE) {
4128 s = bc_lex_next(&p->l);
4132 bc_vec_pop(&p->flags);
4134 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4135 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4137 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4139 else if (BC_PARSE_ELSE(p)) {
4144 bc_vec_pop(&p->flags);
4146 ip = bc_vec_top(&p->exits);
4147 label = bc_vec_item(&p->func->labels, ip->idx);
4148 *label = p->func->code.len;
4150 bc_vec_pop(&p->exits);
4152 else if (BC_PARSE_FUNC_INNER(p)) {
4153 bc_parse_push(p, BC_INST_RET0);
4154 bc_parse_updateFunc(p, BC_PROG_MAIN);
4155 bc_vec_pop(&p->flags);
4159 BcInstPtr *ip = bc_vec_top(&p->exits);
4160 size_t *label = bc_vec_top(&p->conds);
4162 bc_parse_push(p, BC_INST_JUMP);
4163 bc_parse_pushIndex(p, *label);
4165 label = bc_vec_item(&p->func->labels, ip->idx);
4166 *label = p->func->code.len;
4168 bc_vec_pop(&p->flags);
4169 bc_vec_pop(&p->exits);
4170 bc_vec_pop(&p->conds);
4176 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4178 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4179 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4180 flags |= BC_PARSE_FLAG_BODY;
4181 bc_vec_push(&p->flags, &flags);
4184 static void bc_parse_noElse(BcParse *p)
4188 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4190 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4192 ip = bc_vec_top(&p->exits);
4193 label = bc_vec_item(&p->func->labels, ip->idx);
4194 *label = p->func->code.len;
4196 bc_vec_pop(&p->exits);
4199 static BcStatus bc_parse_if(BcParse *p)
4204 s = bc_lex_next(&p->l);
4206 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4208 s = bc_lex_next(&p->l);
4210 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4212 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4214 s = bc_lex_next(&p->l);
4216 bc_parse_push(p, BC_INST_JUMP_ZERO);
4218 ip.idx = p->func->labels.len;
4219 ip.func = ip.len = 0;
4221 bc_parse_pushIndex(p, ip.idx);
4222 bc_vec_push(&p->exits, &ip);
4223 bc_vec_push(&p->func->labels, &ip.idx);
4224 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4226 return BC_STATUS_SUCCESS;
4229 static BcStatus bc_parse_else(BcParse *p)
4233 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4235 ip.idx = p->func->labels.len;
4236 ip.func = ip.len = 0;
4238 bc_parse_push(p, BC_INST_JUMP);
4239 bc_parse_pushIndex(p, ip.idx);
4243 bc_vec_push(&p->exits, &ip);
4244 bc_vec_push(&p->func->labels, &ip.idx);
4245 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4247 return bc_lex_next(&p->l);
4250 static BcStatus bc_parse_while(BcParse *p)
4255 s = bc_lex_next(&p->l);
4257 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4258 s = bc_lex_next(&p->l);
4261 ip.idx = p->func->labels.len;
4263 bc_vec_push(&p->func->labels, &p->func->code.len);
4264 bc_vec_push(&p->conds, &ip.idx);
4266 ip.idx = p->func->labels.len;
4270 bc_vec_push(&p->exits, &ip);
4271 bc_vec_push(&p->func->labels, &ip.idx);
4273 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4275 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4276 s = bc_lex_next(&p->l);
4279 bc_parse_push(p, BC_INST_JUMP_ZERO);
4280 bc_parse_pushIndex(p, ip.idx);
4281 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4283 return BC_STATUS_SUCCESS;
4286 static BcStatus bc_parse_for(BcParse *p)
4290 size_t cond_idx, exit_idx, body_idx, update_idx;
4292 s = bc_lex_next(&p->l);
4294 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4295 s = bc_lex_next(&p->l);
4298 if (p->l.t.t != BC_LEX_SCOLON)
4299 s = bc_parse_expr(p, 0, bc_parse_next_for);
4301 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4304 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4305 s = bc_lex_next(&p->l);
4308 cond_idx = p->func->labels.len;
4309 update_idx = cond_idx + 1;
4310 body_idx = update_idx + 1;
4311 exit_idx = body_idx + 1;
4313 bc_vec_push(&p->func->labels, &p->func->code.len);
4315 if (p->l.t.t != BC_LEX_SCOLON)
4316 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4318 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4321 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4323 s = bc_lex_next(&p->l);
4326 bc_parse_push(p, BC_INST_JUMP_ZERO);
4327 bc_parse_pushIndex(p, exit_idx);
4328 bc_parse_push(p, BC_INST_JUMP);
4329 bc_parse_pushIndex(p, body_idx);
4331 ip.idx = p->func->labels.len;
4333 bc_vec_push(&p->conds, &update_idx);
4334 bc_vec_push(&p->func->labels, &p->func->code.len);
4336 if (p->l.t.t != BC_LEX_RPAREN)
4337 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4339 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4343 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4344 bc_parse_push(p, BC_INST_JUMP);
4345 bc_parse_pushIndex(p, cond_idx);
4346 bc_vec_push(&p->func->labels, &p->func->code.len);
4352 bc_vec_push(&p->exits, &ip);
4353 bc_vec_push(&p->func->labels, &ip.idx);
4355 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4357 return BC_STATUS_SUCCESS;
4360 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4366 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4368 if (type == BC_LEX_KEY_BREAK) {
4370 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4372 i = p->exits.len - 1;
4373 ip = bc_vec_item(&p->exits, i);
4375 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4376 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4381 i = *((size_t *) bc_vec_top(&p->conds));
4383 bc_parse_push(p, BC_INST_JUMP);
4384 bc_parse_pushIndex(p, i);
4386 s = bc_lex_next(&p->l);
4389 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4390 return BC_STATUS_PARSE_BAD_TOKEN;
4392 return bc_lex_next(&p->l);
4395 static BcStatus bc_parse_func(BcParse *p)
4398 bool var, comma = false;
4402 s = bc_lex_next(&p->l);
4404 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4406 name = xstrdup(p->l.t.v.v);
4407 bc_parse_addFunc(p, name, &p->fidx);
4409 s = bc_lex_next(&p->l);
4411 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4412 s = bc_lex_next(&p->l);
4415 while (p->l.t.t != BC_LEX_RPAREN) {
4417 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4421 name = xstrdup(p->l.t.v.v);
4422 s = bc_lex_next(&p->l);
4425 var = p->l.t.t != BC_LEX_LBRACKET;
4429 s = bc_lex_next(&p->l);
4432 if (p->l.t.t != BC_LEX_RBRACKET) {
4433 s = BC_STATUS_PARSE_BAD_FUNC;
4437 s = bc_lex_next(&p->l);
4441 comma = p->l.t.t == BC_LEX_COMMA;
4443 s = bc_lex_next(&p->l);
4447 s = bc_func_insert(p->func, name, var);
4451 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4453 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4454 bc_parse_startBody(p, flags);
4456 s = bc_lex_next(&p->l);
4459 if (p->l.t.t != BC_LEX_LBRACE)
4460 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4469 static BcStatus bc_parse_auto(BcParse *p)
4472 bool comma, var, one;
4475 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4476 s = bc_lex_next(&p->l);
4479 p->auto_part = comma = false;
4480 one = p->l.t.t == BC_LEX_NAME;
4482 while (p->l.t.t == BC_LEX_NAME) {
4484 name = xstrdup(p->l.t.v.v);
4485 s = bc_lex_next(&p->l);
4488 var = p->l.t.t != BC_LEX_LBRACKET;
4491 s = bc_lex_next(&p->l);
4494 if (p->l.t.t != BC_LEX_RBRACKET) {
4495 s = BC_STATUS_PARSE_BAD_FUNC;
4499 s = bc_lex_next(&p->l);
4503 comma = p->l.t.t == BC_LEX_COMMA;
4505 s = bc_lex_next(&p->l);
4509 s = bc_func_insert(p->func, name, var);
4513 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4514 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4516 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4517 return BC_STATUS_PARSE_BAD_TOKEN;
4519 return bc_lex_next(&p->l);
4526 static BcStatus bc_parse_body(BcParse *p, bool brace)
4528 BcStatus s = BC_STATUS_SUCCESS;
4529 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4531 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4533 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4535 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4536 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4538 if (!p->auto_part) {
4539 s = bc_parse_auto(p);
4543 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4546 s = bc_parse_stmt(p);
4547 if (!s && !brace) s = bc_parse_endBody(p, false);
4553 static BcStatus bc_parse_stmt(BcParse *p)
4555 BcStatus s = BC_STATUS_SUCCESS;
4561 return bc_lex_next(&p->l);
4564 case BC_LEX_KEY_ELSE:
4566 p->auto_part = false;
4572 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4575 s = bc_lex_next(&p->l);
4578 return bc_parse_body(p, true);
4581 case BC_LEX_KEY_AUTO:
4583 return bc_parse_auto(p);
4588 p->auto_part = false;
4590 if (BC_PARSE_IF_END(p)) {
4592 return BC_STATUS_SUCCESS;
4594 else if (BC_PARSE_BODY(p))
4595 return bc_parse_body(p, false);
4605 case BC_LEX_OP_MINUS:
4606 case BC_LEX_OP_BOOL_NOT:
4610 case BC_LEX_KEY_IBASE:
4611 case BC_LEX_KEY_LAST:
4612 case BC_LEX_KEY_LENGTH:
4613 case BC_LEX_KEY_OBASE:
4614 case BC_LEX_KEY_READ:
4615 case BC_LEX_KEY_SCALE:
4616 case BC_LEX_KEY_SQRT:
4618 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4622 case BC_LEX_KEY_ELSE:
4624 s = bc_parse_else(p);
4630 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4636 s = bc_parse_endBody(p, true);
4642 s = bc_parse_string(p, BC_INST_PRINT_STR);
4646 case BC_LEX_KEY_BREAK:
4647 case BC_LEX_KEY_CONTINUE:
4649 s = bc_parse_loopExit(p, p->l.t.t);
4653 case BC_LEX_KEY_FOR:
4655 s = bc_parse_for(p);
4659 case BC_LEX_KEY_HALT:
4661 bc_parse_push(p, BC_INST_HALT);
4662 s = bc_lex_next(&p->l);
4672 case BC_LEX_KEY_LIMITS:
4674 // "limits" is a compile-time command,
4675 // the output is produced at _parse time_.
4676 s = bc_lex_next(&p->l);
4678 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4679 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4680 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4681 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4682 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4683 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4684 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4685 printf("Number of vars = %lu\n", BC_MAX_VARS);
4689 case BC_LEX_KEY_PRINT:
4691 s = bc_parse_print(p);
4695 case BC_LEX_KEY_QUIT:
4697 // "quit" is a compile-time command. For example,
4698 // "if (0 == 1) quit" terminates when parsing the statement,
4699 // not when it is executed
4703 case BC_LEX_KEY_RETURN:
4705 s = bc_parse_return(p);
4709 case BC_LEX_KEY_WHILE:
4711 s = bc_parse_while(p);
4717 s = BC_STATUS_PARSE_BAD_TOKEN;
4725 static BcStatus bc_parse_parse(BcParse *p)
4729 if (p->l.t.t == BC_LEX_EOF)
4730 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4731 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4732 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4733 s = bc_parse_func(p);
4736 s = bc_parse_stmt(p);
4738 if (s || G_interrupt)
4739 s = bc_parse_reset(p, s);
4744 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4746 BcStatus s = BC_STATUS_SUCCESS;
4747 BcInst prev = BC_INST_PRINT;
4748 BcLexType top, t = p->l.t.t;
4749 size_t nexprs = 0, ops_bgn = p->ops.len;
4750 uint32_t i, nparens, nrelops;
4751 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4753 paren_first = p->l.t.t == BC_LEX_LPAREN;
4754 nparens = nrelops = 0;
4755 paren_expr = rprn = done = get_token = assign = false;
4758 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4764 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4765 rprn = get_token = bin_last = false;
4769 case BC_LEX_OP_MINUS:
4771 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4772 rprn = get_token = false;
4773 bin_last = prev == BC_INST_MINUS;
4777 case BC_LEX_OP_ASSIGN_POWER:
4778 case BC_LEX_OP_ASSIGN_MULTIPLY:
4779 case BC_LEX_OP_ASSIGN_DIVIDE:
4780 case BC_LEX_OP_ASSIGN_MODULUS:
4781 case BC_LEX_OP_ASSIGN_PLUS:
4782 case BC_LEX_OP_ASSIGN_MINUS:
4783 case BC_LEX_OP_ASSIGN:
4785 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4786 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4787 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4789 s = BC_STATUS_PARSE_BAD_ASSIGN;
4794 case BC_LEX_OP_POWER:
4795 case BC_LEX_OP_MULTIPLY:
4796 case BC_LEX_OP_DIVIDE:
4797 case BC_LEX_OP_MODULUS:
4798 case BC_LEX_OP_PLUS:
4799 case BC_LEX_OP_REL_EQ:
4800 case BC_LEX_OP_REL_LE:
4801 case BC_LEX_OP_REL_GE:
4802 case BC_LEX_OP_REL_NE:
4803 case BC_LEX_OP_REL_LT:
4804 case BC_LEX_OP_REL_GT:
4805 case BC_LEX_OP_BOOL_NOT:
4806 case BC_LEX_OP_BOOL_OR:
4807 case BC_LEX_OP_BOOL_AND:
4809 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4810 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4812 return BC_STATUS_PARSE_BAD_EXP;
4815 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4816 prev = BC_PARSE_TOKEN_INST(t);
4817 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4818 rprn = get_token = false;
4819 bin_last = t != BC_LEX_OP_BOOL_NOT;
4826 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4829 paren_expr = rprn = bin_last = false;
4831 bc_vec_push(&p->ops, &t);
4838 if (bin_last || prev == BC_INST_BOOL_NOT)
4839 return BC_STATUS_PARSE_BAD_EXP;
4842 s = BC_STATUS_SUCCESS;
4847 else if (!paren_expr)
4848 return BC_STATUS_PARSE_EMPTY_EXP;
4851 paren_expr = rprn = true;
4852 get_token = bin_last = false;
4854 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4861 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4864 rprn = get_token = bin_last = false;
4865 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4873 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4875 bc_parse_number(p, &prev, &nexprs);
4876 paren_expr = get_token = true;
4877 rprn = bin_last = false;
4882 case BC_LEX_KEY_IBASE:
4883 case BC_LEX_KEY_LAST:
4884 case BC_LEX_KEY_OBASE:
4886 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4888 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4889 bc_parse_push(p, (char) prev);
4891 paren_expr = get_token = true;
4892 rprn = bin_last = false;
4898 case BC_LEX_KEY_LENGTH:
4899 case BC_LEX_KEY_SQRT:
4901 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4903 s = bc_parse_builtin(p, t, flags, &prev);
4905 rprn = get_token = bin_last = false;
4911 case BC_LEX_KEY_READ:
4913 if (BC_PARSE_LEAF(prev, rprn))
4914 return BC_STATUS_PARSE_BAD_EXP;
4915 else if (flags & BC_PARSE_NOREAD)
4916 s = BC_STATUS_EXEC_REC_READ;
4918 s = bc_parse_read(p);
4921 rprn = get_token = bin_last = false;
4923 prev = BC_INST_READ;
4928 case BC_LEX_KEY_SCALE:
4930 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4932 s = bc_parse_scale(p, &prev, flags);
4934 rprn = get_token = bin_last = false;
4936 prev = BC_INST_SCALE;
4943 s = BC_STATUS_PARSE_BAD_TOKEN;
4948 if (!s && get_token) s = bc_lex_next(&p->l);
4952 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
4954 while (p->ops.len > ops_bgn) {
4956 top = BC_PARSE_TOP_OP(p);
4957 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4959 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4960 return BC_STATUS_PARSE_BAD_EXP;
4962 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4964 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4965 bc_vec_pop(&p->ops);
4968 s = BC_STATUS_PARSE_BAD_EXP;
4969 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4971 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4974 if (!(flags & BC_PARSE_REL) && nrelops) {
4975 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4978 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4979 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4983 if (flags & BC_PARSE_PRINT) {
4984 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4985 bc_parse_push(p, BC_INST_POP);
4991 static void bc_parse_init(BcParse *p, size_t func)
4993 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4996 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4998 return bc_parse_expr(p, flags, bc_parse_next_read);
5003 static BcStatus dc_parse_register(BcParse *p)
5008 s = bc_lex_next(&p->l);
5010 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5012 name = xstrdup(p->l.t.v.v);
5013 bc_parse_pushName(p, name);
5018 static BcStatus dc_parse_string(BcParse *p)
5020 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5021 size_t idx, len = G.prog.strs.len;
5023 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5026 str = xstrdup(p->l.t.v.v);
5027 bc_parse_push(p, BC_INST_STR);
5028 bc_parse_pushIndex(p, len);
5029 bc_vec_push(&G.prog.strs, &str);
5030 bc_parse_addFunc(p, name, &idx);
5032 return bc_lex_next(&p->l);
5035 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5039 bc_parse_push(p, inst);
5041 s = dc_parse_register(p);
5046 bc_parse_push(p, BC_INST_SWAP);
5047 bc_parse_push(p, BC_INST_ASSIGN);
5048 bc_parse_push(p, BC_INST_POP);
5051 return bc_lex_next(&p->l);
5054 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5058 bc_parse_push(p, inst);
5059 bc_parse_push(p, BC_INST_EXEC_COND);
5061 s = dc_parse_register(p);
5064 s = bc_lex_next(&p->l);
5067 if (p->l.t.t == BC_LEX_ELSE) {
5068 s = dc_parse_register(p);
5070 s = bc_lex_next(&p->l);
5073 bc_parse_push(p, BC_PARSE_STREND);
5078 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5080 BcStatus s = BC_STATUS_SUCCESS;
5083 bool assign, get_token = false;
5087 case BC_LEX_OP_REL_EQ:
5088 case BC_LEX_OP_REL_LE:
5089 case BC_LEX_OP_REL_GE:
5090 case BC_LEX_OP_REL_NE:
5091 case BC_LEX_OP_REL_LT:
5092 case BC_LEX_OP_REL_GT:
5094 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5101 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5107 s = dc_parse_string(p);
5114 if (t == BC_LEX_NEG) {
5115 s = bc_lex_next(&p->l);
5117 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5120 bc_parse_number(p, &prev, &p->nbraces);
5122 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5128 case BC_LEX_KEY_READ:
5130 if (flags & BC_PARSE_NOREAD)
5131 s = BC_STATUS_EXEC_REC_READ;
5133 bc_parse_push(p, BC_INST_READ);
5138 case BC_LEX_OP_ASSIGN:
5139 case BC_LEX_STORE_PUSH:
5141 assign = t == BC_LEX_OP_ASSIGN;
5142 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5143 s = dc_parse_mem(p, inst, true, assign);
5148 case BC_LEX_LOAD_POP:
5150 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5151 s = dc_parse_mem(p, inst, true, false);
5155 case BC_LEX_STORE_IBASE:
5156 case BC_LEX_STORE_SCALE:
5157 case BC_LEX_STORE_OBASE:
5159 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5160 s = dc_parse_mem(p, inst, false, true);
5166 s = BC_STATUS_PARSE_BAD_TOKEN;
5172 if (!s && get_token) s = bc_lex_next(&p->l);
5177 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5179 BcStatus s = BC_STATUS_SUCCESS;
5183 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5185 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5187 inst = dc_parse_insts[t];
5189 if (inst != BC_INST_INVALID) {
5190 bc_parse_push(p, inst);
5191 s = bc_lex_next(&p->l);
5194 s = dc_parse_token(p, t, flags);
5197 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5198 bc_parse_push(p, BC_INST_POP_EXEC);
5203 static BcStatus dc_parse_parse(BcParse *p)
5207 if (p->l.t.t == BC_LEX_EOF)
5208 s = BC_STATUS_LEX_EOF;
5210 s = dc_parse_expr(p, 0);
5212 if (s || G_interrupt) s = bc_parse_reset(p, s);
5217 static void dc_parse_init(BcParse *p, size_t func)
5219 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5223 static void common_parse_init(BcParse *p, size_t func)
5226 bc_parse_init(p, func);
5228 dc_parse_init(p, func);
5232 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5235 return bc_parse_expression(p, flags);
5237 return dc_parse_expr(p, flags);
5241 static BcVec* bc_program_search(char *id, bool var)
5250 v = var ? &G.prog.vars : &G.prog.arrs;
5251 map = var ? &G.prog.var_map : &G.prog.arr_map;
5255 s = bc_map_insert(map, &e, &i);
5256 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5259 bc_array_init(&data.v, var);
5260 bc_vec_push(v, &data.v);
5263 ptr = bc_vec_item(map, i);
5264 if (new) ptr->name = xstrdup(e.name);
5265 return bc_vec_item(v, ptr->idx);
5268 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5270 BcStatus s = BC_STATUS_SUCCESS;
5275 case BC_RESULT_TEMP:
5276 case BC_RESULT_IBASE:
5277 case BC_RESULT_SCALE:
5278 case BC_RESULT_OBASE:
5284 case BC_RESULT_CONSTANT:
5286 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5287 size_t base_t, len = strlen(*str);
5290 bc_num_init(&r->d.n, len);
5292 hex = hex && len == 1;
5293 base = hex ? &G.prog.hexb : &G.prog.ib;
5294 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5295 s = bc_num_parse(&r->d.n, *str, base, base_t);
5298 bc_num_free(&r->d.n);
5303 r->t = BC_RESULT_TEMP;
5309 case BC_RESULT_ARRAY:
5310 case BC_RESULT_ARRAY_ELEM:
5314 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5316 if (r->t == BC_RESULT_ARRAY_ELEM) {
5318 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5319 *num = bc_vec_item(v, r->d.id.idx);
5322 *num = bc_vec_top(v);
5327 case BC_RESULT_LAST:
5329 *num = &G.prog.last;
5343 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5344 BcResult **r, BcNum **rn, bool assign)
5348 BcResultType lt, rt;
5350 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5352 *r = bc_vec_item_rev(&G.prog.results, 0);
5353 *l = bc_vec_item_rev(&G.prog.results, 1);
5357 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5359 s = bc_program_num(*l, ln, false);
5361 s = bc_program_num(*r, rn, hex);
5364 // We run this again under these conditions in case any vector has been
5365 // reallocated out from under the BcNums or arrays we had.
5366 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5367 s = bc_program_num(*l, ln, false);
5371 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5372 return BC_STATUS_EXEC_BAD_TYPE;
5373 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5378 static void bc_program_binOpRetire(BcResult *r)
5380 r->t = BC_RESULT_TEMP;
5381 bc_vec_pop(&G.prog.results);
5382 bc_vec_pop(&G.prog.results);
5383 bc_vec_push(&G.prog.results, r);
5386 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5390 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5391 *r = bc_vec_top(&G.prog.results);
5393 s = bc_program_num(*r, n, false);
5396 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5401 static void bc_program_retire(BcResult *r, BcResultType t)
5404 bc_vec_pop(&G.prog.results);
5405 bc_vec_push(&G.prog.results, r);
5408 static BcStatus bc_program_op(char inst)
5411 BcResult *opd1, *opd2, res;
5412 BcNum *n1, *n2 = NULL;
5414 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5416 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5418 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5420 bc_program_binOpRetire(&res);
5425 bc_num_free(&res.d.n);
5429 static BcStatus bc_program_read(void)
5436 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5438 for (i = 0; i < G.prog.stack.len; ++i) {
5439 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5440 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5443 bc_vec_npop(&f->code, f->code.len);
5444 bc_vec_init(&buf, sizeof(char), NULL);
5446 s = bc_read_line(&buf, "read> ");
5449 common_parse_init(&parse, BC_PROG_READ);
5450 bc_lex_file(&parse.l, bc_program_stdin_name);
5452 s = bc_parse_text(&parse, buf.v);
5453 if (s) goto exec_err;
5454 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5455 if (s) goto exec_err;
5457 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5458 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5462 ip.func = BC_PROG_READ;
5464 ip.len = G.prog.results.len;
5466 // Update this pointer, just in case.
5467 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5469 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5470 bc_vec_push(&G.prog.stack, &ip);
5473 bc_parse_free(&parse);
5479 static size_t bc_program_index(char *code, size_t *bgn)
5481 char amt = code[(*bgn)++], i = 0;
5484 for (; i < amt; ++i, ++(*bgn))
5485 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5490 static char *bc_program_name(char *code, size_t *bgn)
5493 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5495 s = xmalloc(ptr - str + 1);
5498 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5506 static void bc_program_printString(const char *str, size_t *nchars)
5508 size_t i, len = strlen(str);
5517 for (i = 0; i < len; ++i, ++(*nchars)) {
5521 if (c != '\\' || i == len - 1)
5581 // Just print the backslash and following character.
5592 static BcStatus bc_program_print(char inst, size_t idx)
5594 BcStatus s = BC_STATUS_SUCCESS;
5599 bool pop = inst != BC_INST_PRINT;
5601 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5603 r = bc_vec_item_rev(&G.prog.results, idx);
5604 s = bc_program_num(r, &num, false);
5607 if (BC_PROG_NUM(r, num)) {
5608 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5609 if (!s) bc_num_copy(&G.prog.last, num);
5613 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5614 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5616 if (inst == BC_INST_PRINT_STR) {
5617 for (i = 0, len = strlen(str); i < len; ++i) {
5620 if (c == '\n') G.prog.nchars = SIZE_MAX;
5625 bc_program_printString(str, &G.prog.nchars);
5626 if (inst == BC_INST_PRINT) bb_putchar('\n');
5630 if (!s && pop) bc_vec_pop(&G.prog.results);
5635 static BcStatus bc_program_negate(void)
5641 s = bc_program_prep(&ptr, &num);
5644 bc_num_init(&res.d.n, num->len);
5645 bc_num_copy(&res.d.n, num);
5646 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5648 bc_program_retire(&res, BC_RESULT_TEMP);
5653 static BcStatus bc_program_logical(char inst)
5656 BcResult *opd1, *opd2, res;
5661 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5663 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5665 if (inst == BC_INST_BOOL_AND)
5666 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5667 else if (inst == BC_INST_BOOL_OR)
5668 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5671 cmp = bc_num_cmp(n1, n2);
5675 case BC_INST_REL_EQ:
5681 case BC_INST_REL_LE:
5687 case BC_INST_REL_GE:
5693 case BC_INST_REL_NE:
5699 case BC_INST_REL_LT:
5705 case BC_INST_REL_GT:
5713 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5715 bc_program_binOpRetire(&res);
5721 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5727 memset(&n2, 0, sizeof(BcNum));
5728 n2.rdx = res.d.id.idx = r->d.id.idx;
5729 res.t = BC_RESULT_STR;
5732 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5734 bc_vec_pop(&G.prog.results);
5737 bc_vec_pop(&G.prog.results);
5739 bc_vec_push(&G.prog.results, &res);
5740 bc_vec_push(v, &n2);
5742 return BC_STATUS_SUCCESS;
5746 static BcStatus bc_program_copyToVar(char *name, bool var)
5753 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5755 ptr = bc_vec_top(&G.prog.results);
5756 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5757 v = bc_program_search(name, var);
5760 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5761 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5764 s = bc_program_num(ptr, &n, false);
5767 // Do this once more to make sure that pointers were not invalidated.
5768 v = bc_program_search(name, var);
5771 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5772 bc_num_copy(&r.d.n, n);
5775 bc_array_init(&r.d.v, true);
5776 bc_array_copy(&r.d.v, (BcVec *) n);
5779 bc_vec_push(v, &r.d);
5780 bc_vec_pop(&G.prog.results);
5785 static BcStatus bc_program_assign(char inst)
5788 BcResult *left, *right, res;
5789 BcNum *l = NULL, *r = NULL;
5790 unsigned long val, max;
5791 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5793 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5796 ib = left->t == BC_RESULT_IBASE;
5797 sc = left->t == BC_RESULT_SCALE;
5801 if (right->t == BC_RESULT_STR) {
5805 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5806 v = bc_program_search(left->d.id.name, true);
5808 return bc_program_assignStr(right, v, false);
5812 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5813 return BC_STATUS_PARSE_BAD_ASSIGN;
5816 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5817 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5822 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5829 if (ib || sc || left->t == BC_RESULT_OBASE) {
5833 s = bc_num_ulong(l, &val);
5835 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5839 ptr = &G.prog.scale;
5842 if (val < BC_NUM_MIN_BASE) return s;
5843 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5844 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5847 if (val > max) return s;
5848 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5850 *ptr = (size_t) val;
5851 s = BC_STATUS_SUCCESS;
5854 bc_num_init(&res.d.n, l->len);
5855 bc_num_copy(&res.d.n, l);
5856 bc_program_binOpRetire(&res);
5862 #define bc_program_pushVar(code, bgn, pop, copy) \
5863 bc_program_pushVar(code, bgn)
5864 // for bc, 'pop' and 'copy' are always false
5866 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5867 bool pop, bool copy)
5869 BcStatus s = BC_STATUS_SUCCESS;
5871 char *name = bc_program_name(code, bgn);
5873 r.t = BC_RESULT_VAR;
5878 BcVec *v = bc_program_search(name, true);
5879 BcNum *num = bc_vec_top(v);
5883 if (!BC_PROG_STACK(v, 2 - copy)) {
5885 return BC_STATUS_EXEC_STACK;
5891 if (!BC_PROG_STR(num)) {
5893 r.t = BC_RESULT_TEMP;
5895 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5896 bc_num_copy(&r.d.n, num);
5899 r.t = BC_RESULT_STR;
5900 r.d.id.idx = num->rdx;
5903 if (!copy) bc_vec_pop(v);
5908 bc_vec_push(&G.prog.results, &r);
5913 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5916 BcStatus s = BC_STATUS_SUCCESS;
5920 r.d.id.name = bc_program_name(code, bgn);
5922 if (inst == BC_INST_ARRAY) {
5923 r.t = BC_RESULT_ARRAY;
5924 bc_vec_push(&G.prog.results, &r);
5931 s = bc_program_prep(&operand, &num);
5933 s = bc_num_ulong(num, &temp);
5936 if (temp > BC_MAX_DIM) {
5937 s = BC_STATUS_EXEC_ARRAY_LEN;
5941 r.d.id.idx = (size_t) temp;
5942 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5946 if (s) free(r.d.id.name);
5951 static BcStatus bc_program_incdec(char inst)
5954 BcResult *ptr, res, copy;
5958 s = bc_program_prep(&ptr, &num);
5961 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5962 copy.t = BC_RESULT_TEMP;
5963 bc_num_init(©.d.n, num->len);
5964 bc_num_copy(©.d.n, num);
5967 res.t = BC_RESULT_ONE;
5968 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5969 BC_INST_ASSIGN_PLUS :
5970 BC_INST_ASSIGN_MINUS;
5972 bc_vec_push(&G.prog.results, &res);
5973 bc_program_assign(inst);
5975 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5976 bc_vec_pop(&G.prog.results);
5977 bc_vec_push(&G.prog.results, ©);
5983 static BcStatus bc_program_call(char *code, size_t *idx)
5985 BcStatus s = BC_STATUS_SUCCESS;
5987 size_t i, nparams = bc_program_index(code, idx);
5994 ip.func = bc_program_index(code, idx);
5995 func = bc_vec_item(&G.prog.fns, ip.func);
5997 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
5998 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
5999 ip.len = G.prog.results.len - nparams;
6001 for (i = 0; i < nparams; ++i) {
6003 a = bc_vec_item(&func->autos, nparams - 1 - i);
6004 arg = bc_vec_top(&G.prog.results);
6006 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6007 return BC_STATUS_EXEC_BAD_TYPE;
6009 s = bc_program_copyToVar(a->name, a->idx);
6013 for (; i < func->autos.len; ++i) {
6016 a = bc_vec_item(&func->autos, i);
6017 v = bc_program_search(a->name, a->idx);
6020 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6021 bc_vec_push(v, ¶m.n);
6024 bc_array_init(¶m.v, true);
6025 bc_vec_push(v, ¶m.v);
6029 bc_vec_push(&G.prog.stack, &ip);
6031 return BC_STATUS_SUCCESS;
6034 static BcStatus bc_program_return(char inst)
6040 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6042 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6043 return BC_STATUS_EXEC_STACK;
6045 f = bc_vec_item(&G.prog.fns, ip->func);
6046 res.t = BC_RESULT_TEMP;
6048 if (inst == BC_INST_RET) {
6051 BcResult *operand = bc_vec_top(&G.prog.results);
6053 s = bc_program_num(operand, &num, false);
6055 bc_num_init(&res.d.n, num->len);
6056 bc_num_copy(&res.d.n, num);
6059 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6060 bc_num_zero(&res.d.n);
6063 // We need to pop arguments as well, so this takes that into account.
6064 for (i = 0; i < f->autos.len; ++i) {
6067 BcId *a = bc_vec_item(&f->autos, i);
6069 v = bc_program_search(a->name, a->idx);
6073 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6074 bc_vec_push(&G.prog.results, &res);
6075 bc_vec_pop(&G.prog.stack);
6077 return BC_STATUS_SUCCESS;
6081 static unsigned long bc_program_scale(BcNum *n)
6083 return (unsigned long) n->rdx;
6086 static unsigned long bc_program_len(BcNum *n)
6088 unsigned long len = n->len;
6091 if (n->rdx != n->len) return len;
6092 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6097 static BcStatus bc_program_builtin(char inst)
6103 bool len = inst == BC_INST_LENGTH;
6105 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6106 opnd = bc_vec_top(&G.prog.results);
6108 s = bc_program_num(opnd, &num, false);
6112 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6115 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6117 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6119 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6120 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6124 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6127 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6129 str = bc_vec_item(&G.prog.strs, idx);
6130 bc_num_ulong2num(&res.d.n, strlen(*str));
6134 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6135 bc_num_ulong2num(&res.d.n, f(num));
6138 bc_program_retire(&res, BC_RESULT_TEMP);
6144 static BcStatus bc_program_divmod(void)
6147 BcResult *opd1, *opd2, res, res2;
6148 BcNum *n1, *n2 = NULL;
6150 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6153 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6154 bc_num_init(&res2.d.n, n2->len);
6156 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6159 bc_program_binOpRetire(&res2);
6160 res.t = BC_RESULT_TEMP;
6161 bc_vec_push(&G.prog.results, &res);
6166 bc_num_free(&res2.d.n);
6167 bc_num_free(&res.d.n);
6171 static BcStatus bc_program_modexp(void)
6174 BcResult *r1, *r2, *r3, res;
6175 BcNum *n1, *n2, *n3;
6177 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6178 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6181 r1 = bc_vec_item_rev(&G.prog.results, 2);
6182 s = bc_program_num(r1, &n1, false);
6184 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6186 // Make sure that the values have their pointers updated, if necessary.
6187 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6189 if (r1->t == r2->t) {
6190 s = bc_program_num(r2, &n2, false);
6194 if (r1->t == r3->t) {
6195 s = bc_program_num(r3, &n3, false);
6200 bc_num_init(&res.d.n, n3->len);
6201 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6204 bc_vec_pop(&G.prog.results);
6205 bc_program_binOpRetire(&res);
6210 bc_num_free(&res.d.n);
6214 static void bc_program_stackLen(void)
6217 size_t len = G.prog.results.len;
6219 res.t = BC_RESULT_TEMP;
6221 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6222 bc_num_ulong2num(&res.d.n, len);
6223 bc_vec_push(&G.prog.results, &res);
6226 static BcStatus bc_program_asciify(void)
6230 BcNum *num = NULL, n;
6231 char *str, *str2, c;
6232 size_t len = G.prog.strs.len, idx;
6235 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6236 r = bc_vec_top(&G.prog.results);
6238 s = bc_program_num(r, &num, false);
6241 if (BC_PROG_NUM(r, num)) {
6243 bc_num_init(&n, BC_NUM_DEF_SIZE);
6244 bc_num_copy(&n, num);
6245 bc_num_truncate(&n, n.rdx);
6247 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6248 if (s) goto num_err;
6249 s = bc_num_ulong(&n, &val);
6250 if (s) goto num_err;
6257 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6258 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6266 str2 = xstrdup(str);
6267 bc_program_addFunc(str2, &idx);
6269 if (idx != len + BC_PROG_REQ_FUNCS) {
6271 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6272 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6281 bc_vec_push(&G.prog.strs, &str);
6283 res.t = BC_RESULT_STR;
6285 bc_vec_pop(&G.prog.results);
6286 bc_vec_push(&G.prog.results, &res);
6288 return BC_STATUS_SUCCESS;
6295 static BcStatus bc_program_printStream(void)
6303 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6304 r = bc_vec_top(&G.prog.results);
6306 s = bc_program_num(r, &n, false);
6309 if (BC_PROG_NUM(r, n))
6310 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6312 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6313 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6320 static BcStatus bc_program_nquit(void)
6327 s = bc_program_prep(&opnd, &num);
6329 s = bc_num_ulong(num, &val);
6332 bc_vec_pop(&G.prog.results);
6334 if (G.prog.stack.len < val)
6335 return BC_STATUS_EXEC_STACK;
6336 if (G.prog.stack.len == val)
6339 bc_vec_npop(&G.prog.stack, val);
6344 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6347 BcStatus s = BC_STATUS_SUCCESS;
6357 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6359 r = bc_vec_top(&G.prog.results);
6363 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6365 if (code[*bgn] == BC_PARSE_STREND)
6368 else_name = bc_program_name(code, bgn);
6370 exec = r->d.n.len != 0;
6374 else if (else_name != NULL) {
6381 v = bc_program_search(name, true);
6388 if (!exec) goto exit;
6389 if (!BC_PROG_STR(n)) {
6390 s = BC_STATUS_EXEC_BAD_TYPE;
6398 if (r->t == BC_RESULT_STR)
6400 else if (r->t == BC_RESULT_VAR) {
6401 s = bc_program_num(r, &n, false);
6402 if (s || !BC_PROG_STR(n)) goto exit;
6409 fidx = sidx + BC_PROG_REQ_FUNCS;
6411 str = bc_vec_item(&G.prog.strs, sidx);
6412 f = bc_vec_item(&G.prog.fns, fidx);
6414 if (f->code.len == 0) {
6415 common_parse_init(&prs, fidx);
6416 s = bc_parse_text(&prs, *str);
6418 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6421 if (prs.l.t.t != BC_LEX_EOF) {
6422 s = BC_STATUS_PARSE_BAD_EXP;
6426 bc_parse_free(&prs);
6430 ip.len = G.prog.results.len;
6433 bc_vec_pop(&G.prog.results);
6434 bc_vec_push(&G.prog.stack, &ip);
6436 return BC_STATUS_SUCCESS;
6439 bc_parse_free(&prs);
6440 f = bc_vec_item(&G.prog.fns, fidx);
6441 bc_vec_npop(&f->code, f->code.len);
6443 bc_vec_pop(&G.prog.results);
6448 static void bc_program_pushGlobal(char inst)
6453 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6454 if (inst == BC_INST_IBASE)
6455 val = (unsigned long) G.prog.ib_t;
6456 else if (inst == BC_INST_SCALE)
6457 val = (unsigned long) G.prog.scale;
6459 val = (unsigned long) G.prog.ob_t;
6461 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6462 bc_num_ulong2num(&res.d.n, val);
6463 bc_vec_push(&G.prog.results, &res);
6466 static void bc_program_addFunc(char *name, size_t *idx)
6469 BcId entry, *entry_ptr;
6473 entry.idx = G.prog.fns.len;
6475 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
6478 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6479 *idx = entry_ptr->idx;
6481 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6483 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6485 // We need to reset these, so the function can be repopulated.
6487 bc_vec_npop(&func->autos, func->autos.len);
6488 bc_vec_npop(&func->code, func->code.len);
6489 bc_vec_npop(&func->labels, func->labels.len);
6493 bc_vec_push(&G.prog.fns, &f);
6497 static BcStatus bc_program_reset(BcStatus s)
6502 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6503 bc_vec_npop(&G.prog.results, G.prog.results.len);
6505 f = bc_vec_item(&G.prog.fns, 0);
6506 ip = bc_vec_top(&G.prog.stack);
6507 ip->idx = f->code.len;
6509 if (!s && G_interrupt && !G.tty) quit();
6511 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6514 fflush_and_check(); // make sure buffered stdout is printed
6515 fputs(bc_program_ready_msg, stderr);
6517 s = BC_STATUS_SUCCESS;
6523 static BcStatus bc_program_exec(void)
6525 BcStatus s = BC_STATUS_SUCCESS;
6529 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6530 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6531 char *code = func->code.v;
6534 while (!s && ip->idx < func->code.len) {
6536 char inst = code[(ip->idx)++];
6541 case BC_INST_JUMP_ZERO:
6543 s = bc_program_prep(&ptr, &num);
6545 cond = !bc_num_cmp(num, &G.prog.zero);
6546 bc_vec_pop(&G.prog.results);
6552 idx = bc_program_index(code, &ip->idx);
6553 addr = bc_vec_item(&func->labels, idx);
6554 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6560 s = bc_program_call(code, &ip->idx);
6564 case BC_INST_INC_PRE:
6565 case BC_INST_DEC_PRE:
6566 case BC_INST_INC_POST:
6567 case BC_INST_DEC_POST:
6569 s = bc_program_incdec(inst);
6582 s = bc_program_return(inst);
6586 case BC_INST_BOOL_OR:
6587 case BC_INST_BOOL_AND:
6589 case BC_INST_REL_EQ:
6590 case BC_INST_REL_LE:
6591 case BC_INST_REL_GE:
6592 case BC_INST_REL_NE:
6593 case BC_INST_REL_LT:
6594 case BC_INST_REL_GT:
6596 s = bc_program_logical(inst);
6602 s = bc_program_read();
6608 s = bc_program_pushVar(code, &ip->idx, false, false);
6612 case BC_INST_ARRAY_ELEM:
6615 s = bc_program_pushArray(code, &ip->idx, inst);
6621 r.t = BC_RESULT_LAST;
6622 bc_vec_push(&G.prog.results, &r);
6630 bc_program_pushGlobal(inst);
6634 case BC_INST_SCALE_FUNC:
6635 case BC_INST_LENGTH:
6638 s = bc_program_builtin(inst);
6644 r.t = BC_RESULT_CONSTANT;
6645 r.d.id.idx = bc_program_index(code, &ip->idx);
6646 bc_vec_push(&G.prog.results, &r);
6652 if (!BC_PROG_STACK(&G.prog.results, 1))
6653 s = BC_STATUS_EXEC_STACK;
6655 bc_vec_pop(&G.prog.results);
6659 case BC_INST_POP_EXEC:
6661 bc_vec_pop(&G.prog.stack);
6666 case BC_INST_PRINT_POP:
6667 case BC_INST_PRINT_STR:
6669 s = bc_program_print(inst, 0);
6675 r.t = BC_RESULT_STR;
6676 r.d.id.idx = bc_program_index(code, &ip->idx);
6677 bc_vec_push(&G.prog.results, &r);
6682 case BC_INST_MULTIPLY:
6683 case BC_INST_DIVIDE:
6684 case BC_INST_MODULUS:
6688 s = bc_program_op(inst);
6692 case BC_INST_BOOL_NOT:
6694 s = bc_program_prep(&ptr, &num);
6697 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6698 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6699 bc_program_retire(&r, BC_RESULT_TEMP);
6706 s = bc_program_negate();
6711 case BC_INST_ASSIGN_POWER:
6712 case BC_INST_ASSIGN_MULTIPLY:
6713 case BC_INST_ASSIGN_DIVIDE:
6714 case BC_INST_ASSIGN_MODULUS:
6715 case BC_INST_ASSIGN_PLUS:
6716 case BC_INST_ASSIGN_MINUS:
6718 case BC_INST_ASSIGN:
6720 s = bc_program_assign(inst);
6724 case BC_INST_MODEXP:
6726 s = bc_program_modexp();
6730 case BC_INST_DIVMOD:
6732 s = bc_program_divmod();
6736 case BC_INST_EXECUTE:
6737 case BC_INST_EXEC_COND:
6739 cond = inst == BC_INST_EXEC_COND;
6740 s = bc_program_execStr(code, &ip->idx, cond);
6744 case BC_INST_PRINT_STACK:
6746 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6747 s = bc_program_print(BC_INST_PRINT, idx);
6751 case BC_INST_CLEAR_STACK:
6753 bc_vec_npop(&G.prog.results, G.prog.results.len);
6757 case BC_INST_STACK_LEN:
6759 bc_program_stackLen();
6763 case BC_INST_DUPLICATE:
6765 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6766 ptr = bc_vec_top(&G.prog.results);
6767 bc_result_copy(&r, ptr);
6768 bc_vec_push(&G.prog.results, &r);
6776 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6778 ptr = bc_vec_item_rev(&G.prog.results, 0);
6779 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6780 memcpy(&r, ptr, sizeof(BcResult));
6781 memcpy(ptr, ptr2, sizeof(BcResult));
6782 memcpy(ptr2, &r, sizeof(BcResult));
6787 case BC_INST_ASCIIFY:
6789 s = bc_program_asciify();
6793 case BC_INST_PRINT_STREAM:
6795 s = bc_program_printStream();
6800 case BC_INST_PUSH_VAR:
6802 bool copy = inst == BC_INST_LOAD;
6803 s = bc_program_pushVar(code, &ip->idx, true, copy);
6807 case BC_INST_PUSH_TO_VAR:
6809 char *name = bc_program_name(code, &ip->idx);
6810 s = bc_program_copyToVar(name, true);
6817 if (G.prog.stack.len <= 2)
6819 bc_vec_npop(&G.prog.stack, 2);
6825 s = bc_program_nquit();
6831 if (s || G_interrupt) s = bc_program_reset(s);
6833 // If the stack has changed, pointers may be invalid.
6834 ip = bc_vec_top(&G.prog.stack);
6835 func = bc_vec_item(&G.prog.fns, ip->func);
6836 code = func->code.v;
6842 static void bc_vm_info(void)
6844 printf("%s "BB_VER"\n"
6845 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6846 "Report bugs at: https://github.com/gavinhoward/bc\n"
6847 "This is free software with ABSOLUTELY NO WARRANTY\n"
6851 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6853 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6855 fprintf(stderr, bc_err_fmt, bc_err_msgs[s]);
6856 fprintf(stderr, " %s", file);
6857 fprintf(stderr, bc_err_line + 4 * !line, line);
6859 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6863 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6868 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W))) return BC_STATUS_SUCCESS;
6869 if (s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6871 fmt = G_posix ? bc_err_fmt : bc_warn_fmt;
6872 fprintf(stderr, fmt, bc_err_msgs[s]);
6873 if (msg) fprintf(stderr, " %s\n", msg);
6874 fprintf(stderr, " %s", file);
6875 fprintf(stderr, bc_err_line + 4 * !line, line);
6877 if (G.ttyin || !G_posix)
6878 s = BC_STATUS_SUCCESS;
6882 static void bc_vm_envArgs(void)
6884 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6887 char *env_args = getenv(bc_args_env_name), *buf;
6889 if (!env_args) return;
6891 G.env_args = xstrdup(env_args);
6894 bc_vec_init(&v, sizeof(char *), NULL);
6895 bc_vec_push(&v, &bc_args_env_name);
6898 if (!isspace(*buf)) {
6899 bc_vec_push(&v, &buf);
6900 while (*buf != 0 && !isspace(*buf)) ++buf;
6901 if (*buf != 0) (*(buf++)) = '\0';
6907 bc_args((int) v.len, (char **) v.v);
6913 static size_t bc_vm_envLen(const char *var)
6915 char *lenv = getenv(var);
6916 size_t i, len = BC_NUM_PRINT_WIDTH;
6919 if (!lenv) return len;
6923 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6925 len = (size_t) atoi(lenv) - 1;
6926 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6929 len = BC_NUM_PRINT_WIDTH;
6934 static BcStatus bc_vm_process(const char *text)
6936 BcStatus s = bc_parse_text(&G.prs, text);
6938 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6941 while (G.prs.l.t.t != BC_LEX_EOF) {
6943 s = G.prs.parse(&G.prs);
6945 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6949 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6950 s = bc_program_exec();
6953 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
6959 static BcStatus bc_vm_file(const char *file)
6967 data = bc_read_file(file);
6968 if (!data) return bc_error("file '%s' is not text", file);
6970 bc_lex_file(&G.prs.l, file);
6971 s = bc_vm_process(data);
6974 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6975 ip = bc_vec_item(&G.prog.stack, 0);
6977 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
6984 static BcStatus bc_vm_stdin(void)
6988 size_t len, i, str = 0;
6989 bool comment = false;
6991 G.prog.file = bc_program_stdin_name;
6992 bc_lex_file(&G.prs.l, bc_program_stdin_name);
6994 bc_vec_init(&buffer, sizeof(char), NULL);
6995 bc_vec_init(&buf, sizeof(char), NULL);
6996 bc_vec_pushByte(&buffer, '\0');
6998 // This loop is complex because the vm tries not to send any lines that end
6999 // with a backslash to the parser. The reason for that is because the parser
7000 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7001 // case, and for strings and comments, the parser will expect more stuff.
7002 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7004 char *string = buf.v;
7009 if (str && buf.v[0] == G.send)
7011 else if (buf.v[0] == G.sbgn)
7014 else if (len > 1 || comment) {
7016 for (i = 0; i < len; ++i) {
7018 bool notend = len > i + 1;
7021 if (i - 1 > len || string[i - 1] != '\\') {
7022 if (G.sbgn == G.send)
7024 else if (c == G.send)
7026 else if (c == G.sbgn)
7030 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7034 else if (c == '*' && notend && comment && string[i + 1] == '/')
7038 if (str || comment || string[len - 2] == '\\') {
7039 bc_vec_concat(&buffer, buf.v);
7044 bc_vec_concat(&buffer, buf.v);
7045 s = bc_vm_process(buffer.v);
7048 bc_vec_npop(&buffer, buffer.len);
7052 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7055 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7060 bc_vec_free(&buffer);
7064 static BcStatus bc_vm_exec(void)
7066 BcStatus s = BC_STATUS_SUCCESS;
7070 if (G.flags & BC_FLAG_L) {
7072 bc_lex_file(&G.prs.l, bc_lib_name);
7073 s = bc_parse_text(&G.prs, bc_lib);
7075 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7078 s = bc_program_exec();
7083 for (i = 0; !s && i < G.files.len; ++i)
7084 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7087 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7088 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7093 #if ENABLE_FEATURE_CLEAN_UP
7094 static void bc_program_free()
7096 bc_num_free(&G.prog.ib);
7097 bc_num_free(&G.prog.ob);
7098 bc_num_free(&G.prog.hexb);
7100 bc_num_free(&G.prog.strmb);
7102 bc_vec_free(&G.prog.fns);
7103 bc_vec_free(&G.prog.fn_map);
7104 bc_vec_free(&G.prog.vars);
7105 bc_vec_free(&G.prog.var_map);
7106 bc_vec_free(&G.prog.arrs);
7107 bc_vec_free(&G.prog.arr_map);
7108 bc_vec_free(&G.prog.strs);
7109 bc_vec_free(&G.prog.consts);
7110 bc_vec_free(&G.prog.results);
7111 bc_vec_free(&G.prog.stack);
7112 bc_num_free(&G.prog.last);
7113 bc_num_free(&G.prog.zero);
7114 bc_num_free(&G.prog.one);
7117 static void bc_vm_free(void)
7119 bc_vec_free(&G.files);
7121 bc_parse_free(&G.prs);
7126 static void bc_program_init(size_t line_len)
7131 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7132 memset(&ip, 0, sizeof(BcInstPtr));
7134 /* G.prog.nchars = G.prog.scale = 0; - already is */
7135 G.prog.len = line_len;
7137 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7138 bc_num_ten(&G.prog.ib);
7141 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7142 bc_num_ten(&G.prog.ob);
7145 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7146 bc_num_ten(&G.prog.hexb);
7147 G.prog.hexb.num[0] = 6;
7150 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7151 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7154 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7155 bc_num_zero(&G.prog.last);
7157 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7158 bc_num_zero(&G.prog.zero);
7160 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7161 bc_num_one(&G.prog.one);
7163 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7164 bc_map_init(&G.prog.fn_map);
7166 bc_program_addFunc(xstrdup("(main)"), &idx);
7167 bc_program_addFunc(xstrdup("(read)"), &idx);
7169 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7170 bc_map_init(&G.prog.var_map);
7172 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7173 bc_map_init(&G.prog.arr_map);
7175 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7176 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7177 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7178 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7179 bc_vec_push(&G.prog.stack, &ip);
7182 static void bc_vm_init(const char *env_len)
7184 size_t len = bc_vm_envLen(env_len);
7186 #if ENABLE_FEATURE_BC_SIGNALS
7187 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7190 bc_vec_init(&G.files, sizeof(char *), NULL);
7193 if (getenv("POSIXLY_CORRECT"))
7194 G.flags |= BC_FLAG_S;
7198 bc_program_init(len);
7200 bc_parse_init(&G.prs, BC_PROG_MAIN);
7202 dc_parse_init(&G.prs, BC_PROG_MAIN);
7206 static BcStatus bc_vm_run(int argc, char *argv[],
7207 const char *env_len)
7211 bc_vm_init(env_len);
7212 bc_args(argc, argv);
7214 G.ttyin = isatty(0);
7215 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7217 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7220 #if ENABLE_FEATURE_CLEAN_UP
7227 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7228 int bc_main(int argc, char **argv)
7231 G.sbgn = G.send = '"';
7233 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7238 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7239 int dc_main(int argc, char **argv)
7245 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");