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 //usage:#define bc_trivial_usage
118 //usage: "EXPRESSION...\n"
119 //usage: "function_definition\n"
121 //usage:#define bc_full_usage "\n\n"
122 //usage: "See www.gnu.org/software/bc/manual/bc.html\n"
124 //usage:#define bc_example_usage
125 //usage: "3 + 4.129\n"
126 //usage: "1903 - 2893\n"
127 //usage: "-129 * 213.28935\n"
128 //usage: "12 / -1932\n"
130 //usage: "34 ^ 189\n"
131 //usage: "scale = 13\n"
132 //usage: "ibase = 2\n"
133 //usage: "obase = A\n"
135 //usage:#define dc_trivial_usage
136 //usage: "EXPRESSION..."
138 //usage:#define dc_full_usage "\n\n"
139 //usage: "Tiny RPN calculator. Operations:\n"
140 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
141 //usage: "modular exponentiation,\n"
142 //usage: "p - print top of the stack (without popping),\n"
143 //usage: "f - print entire stack,\n"
144 //usage: "k - pop the value and set the precision.\n"
145 //usage: "i - pop the value and set input radix.\n"
146 //usage: "o - pop the value and set output radix.\n"
147 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
149 //usage:#define dc_example_usage
150 //usage: "$ dc 2 2 + p\n"
152 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
154 //usage: "$ dc 0 1 and p\n"
156 //usage: "$ dc 0 1 or p\n"
158 //usage: "$ echo 72 9 div 8 mul p | dc\n"
163 typedef enum BcStatus {
170 BC_STATUS_PATH_IS_DIR,
172 BC_STATUS_LEX_BAD_CHAR,
173 BC_STATUS_LEX_NO_STRING_END,
174 BC_STATUS_LEX_NO_COMMENT_END,
177 BC_STATUS_LEX_EXTENDED_REG,
180 BC_STATUS_PARSE_BAD_TOKEN,
181 BC_STATUS_PARSE_BAD_EXP,
182 BC_STATUS_PARSE_EMPTY_EXP,
183 BC_STATUS_PARSE_BAD_PRINT,
184 BC_STATUS_PARSE_BAD_FUNC,
185 BC_STATUS_PARSE_BAD_ASSIGN,
186 BC_STATUS_PARSE_NO_AUTO,
187 BC_STATUS_PARSE_DUPLICATE_LOCAL,
188 BC_STATUS_PARSE_NO_BLOCK_END,
190 BC_STATUS_MATH_NEGATIVE,
191 BC_STATUS_MATH_NON_INTEGER,
192 BC_STATUS_MATH_OVERFLOW,
193 BC_STATUS_MATH_DIVIDE_BY_ZERO,
194 BC_STATUS_MATH_BAD_STRING,
196 BC_STATUS_EXEC_FILE_ERR,
197 BC_STATUS_EXEC_MISMATCHED_PARAMS,
198 BC_STATUS_EXEC_UNDEFINED_FUNC,
199 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
200 BC_STATUS_EXEC_NUM_LEN,
201 BC_STATUS_EXEC_NAME_LEN,
202 BC_STATUS_EXEC_STRING_LEN,
203 BC_STATUS_EXEC_ARRAY_LEN,
204 BC_STATUS_EXEC_BAD_IBASE,
205 BC_STATUS_EXEC_BAD_SCALE,
206 BC_STATUS_EXEC_BAD_READ_EXPR,
207 BC_STATUS_EXEC_REC_READ,
208 BC_STATUS_EXEC_BAD_TYPE,
209 BC_STATUS_EXEC_BAD_OBASE,
210 BC_STATUS_EXEC_SIGNAL,
211 BC_STATUS_EXEC_STACK,
213 BC_STATUS_VEC_OUT_OF_BOUNDS,
214 BC_STATUS_VEC_ITEM_EXISTS,
217 BC_STATUS_POSIX_NAME_LEN,
218 BC_STATUS_POSIX_COMMENT,
219 BC_STATUS_POSIX_BAD_KW,
222 BC_STATUS_POSIX_BOOL,
223 BC_STATUS_POSIX_REL_POS,
224 BC_STATUS_POSIX_MULTIREL,
225 BC_STATUS_POSIX_FOR1,
226 BC_STATUS_POSIX_FOR2,
227 BC_STATUS_POSIX_FOR3,
228 BC_STATUS_POSIX_BRACE,
234 BC_STATUS_INVALID_OPTION,
238 #define BC_ERR_IDX_VM (0)
239 #define BC_ERR_IDX_LEX (1)
240 #define BC_ERR_IDX_PARSE (2)
241 #define BC_ERR_IDX_MATH (3)
242 #define BC_ERR_IDX_EXEC (4)
243 #define BC_ERR_IDX_VEC (5)
245 #define BC_ERR_IDX_POSIX (6)
248 #define BC_VEC_INVALID_IDX ((size_t) -1)
249 #define BC_VEC_START_CAP (1 << 5)
251 typedef void (*BcVecFree)(void *);
252 typedef int (*BcVecCmp)(const void *, const void *);
254 typedef struct BcVec {
262 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
263 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
265 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
267 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
269 typedef signed char BcDig;
271 typedef struct BcNum {
279 #define BC_NUM_MIN_BASE ((unsigned long) 2)
280 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
281 #define BC_NUM_DEF_SIZE (16)
282 #define BC_NUM_PRINT_WIDTH (69)
284 #define BC_NUM_KARATSUBA_LEN (32)
286 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
287 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
288 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
289 #define BC_NUM_AREQ(a, b) \
290 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
291 #define BC_NUM_MREQ(a, b, scale) \
292 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
294 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
295 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
297 static void bc_num_init(BcNum *n, size_t req);
298 static void bc_num_expand(BcNum *n, size_t req);
299 static void bc_num_copy(BcNum *d, BcNum *s);
300 static void bc_num_free(void *num);
302 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
303 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val);
305 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
308 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
309 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
310 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
311 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
312 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
315 typedef enum BcInst {
345 BC_INST_ASSIGN_POWER,
346 BC_INST_ASSIGN_MULTIPLY,
347 BC_INST_ASSIGN_DIVIDE,
348 BC_INST_ASSIGN_MODULUS,
350 BC_INST_ASSIGN_MINUS,
396 BC_INST_PRINT_STREAM,
411 BC_INST_INVALID = -1,
416 typedef struct BcId {
421 typedef struct BcFunc {
428 typedef enum BcResultType {
433 BC_RESULT_ARRAY_ELEM,
442 // These are between to calculate ibase, obase, and last from instructions.
450 typedef union BcResultData {
456 typedef struct BcResult {
461 typedef struct BcInstPtr {
467 static void bc_array_expand(BcVec *a, size_t len);
468 static int bc_id_cmp(const void *e1, const void *e2);
470 // BC_LEX_NEG is not used in lexing; it is only for parsing.
471 typedef enum BcLexType {
499 BC_LEX_OP_ASSIGN_POWER,
500 BC_LEX_OP_ASSIGN_MULTIPLY,
501 BC_LEX_OP_ASSIGN_DIVIDE,
502 BC_LEX_OP_ASSIGN_MODULUS,
503 BC_LEX_OP_ASSIGN_PLUS,
504 BC_LEX_OP_ASSIGN_MINUS,
578 typedef BcStatus (*BcLexNext)(struct BcLex *);
580 typedef struct BcLex {
599 #define BC_PARSE_STREND ((char) UCHAR_MAX)
601 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
602 #define bc_parse_updateFunc(p, f) \
603 ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f))))
605 #define BC_PARSE_REL (1 << 0)
606 #define BC_PARSE_PRINT (1 << 1)
607 #define BC_PARSE_NOCALL (1 << 2)
608 #define BC_PARSE_NOREAD (1 << 3)
609 #define BC_PARSE_ARRAY (1 << 4)
611 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
612 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
614 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
615 #define BC_PARSE_FUNC_INNER(parse) \
616 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
618 #define BC_PARSE_FLAG_FUNC (1 << 1)
619 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
621 #define BC_PARSE_FLAG_BODY (1 << 2)
622 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
624 #define BC_PARSE_FLAG_LOOP (1 << 3)
625 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
627 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
628 #define BC_PARSE_LOOP_INNER(parse) \
629 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
631 #define BC_PARSE_FLAG_IF (1 << 5)
632 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
634 #define BC_PARSE_FLAG_ELSE (1 << 6)
635 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
637 #define BC_PARSE_FLAG_IF_END (1 << 7)
638 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
640 #define BC_PARSE_CAN_EXEC(parse) \
641 (!(BC_PARSE_TOP_FLAG(parse) & \
642 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
643 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
644 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
646 typedef struct BcOp {
651 typedef struct BcParseNext {
656 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
657 #define BC_PARSE_NEXT(a, ...) \
659 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
666 typedef void (*BcParseInit)(struct BcParse *, struct BcProgram *, size_t);
667 typedef BcStatus (*BcParseParse)(struct BcParse *);
668 typedef BcStatus (*BcParseExpr)(struct BcParse *, uint8_t);
670 typedef struct BcParse {
683 struct BcProgram *prog;
694 BcStatus bc_main(int argc, char *argv[]);
696 typedef struct BcLexKeyword {
702 #define BC_LEX_KW_ENTRY(a, b, c) \
704 .name = a, .len = (b), .posix = (c) \
707 static BcStatus bc_lex_token(BcLex *l);
709 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
710 #define BC_PARSE_LEAF(p, rparen) \
711 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
712 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
714 // We can calculate the conversion between tokens and exprs by subtracting the
715 // position of the first operator in the lex enum and adding the position of the
716 // first in the expr enum. Note: This only works for binary operators.
717 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
719 static BcStatus bc_parse_parse(BcParse *p);
720 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
726 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
728 BcStatus dc_main(int argc, char *argv[]);
730 static BcStatus dc_lex_token(BcLex *l);
732 static void dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
733 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
737 typedef struct BcProgram {
776 BcParseInit parse_init;
777 BcParseExpr parse_expr;
781 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
783 #define BC_PROG_MAIN (0)
784 #define BC_PROG_READ (1)
787 #define BC_PROG_REQ_FUNCS (2)
790 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
791 #define BC_PROG_NUM(r, n) \
792 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
794 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
796 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx);
797 static BcStatus bc_program_reset(BcProgram *p, BcStatus s);
798 static BcStatus bc_program_exec(BcProgram *p);
800 #define BC_FLAG_X (1 << 0)
801 #define BC_FLAG_W (1 << 1)
802 #define BC_FLAG_V (1 << 2)
803 #define BC_FLAG_S (1 << 3)
804 #define BC_FLAG_Q (1 << 4)
805 #define BC_FLAG_L (1 << 5)
806 #define BC_FLAG_I (1 << 6)
808 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
809 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
811 #define BC_MAX_OBASE ((unsigned long) 999)
812 #define BC_MAX_DIM ((unsigned long) INT_MAX)
813 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
814 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
815 #define BC_MAX_NAME BC_MAX_STRING
816 #define BC_MAX_NUM BC_MAX_STRING
817 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
818 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
820 typedef struct BcVmExe {
827 typedef struct BcVm {
840 typedef struct BcGlobals {
852 #if ENABLE_FEATURE_BC_SIGNALS
859 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
862 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
866 static void bc_vm_info(void);
867 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
868 const char *env_len);
870 static BcGlobals bcg;
873 # if ENABLE_FEATURE_BC_SIGNALS
874 static const char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n";
879 # if ENABLE_FEATURE_BC_SIGNALS
880 static const char dc_sig_msg[] = "\ninterrupt (type \"q\" to exit)\n";
884 static const char* const bc_args_env_name = "BC_ENV_ARGS";
886 static const char bc_err_fmt[] = "\n%s error: %s\n";
887 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
888 static const char bc_err_line[] = ":%zu\n\n";
890 static const char *bc_errs[] = {
902 static const uint8_t bc_err_ids[] = {
903 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
904 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
908 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
909 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
910 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
915 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
916 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
917 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
918 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
920 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
922 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
923 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
924 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
926 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
929 static const char *bc_err_msgs[] = {
932 "memory allocation error",
935 "path is a directory:",
938 "string end could not be found",
939 "comment end could not be found",
948 "bad print statement",
949 "bad function definition",
950 "bad assignment: left side must be scale, ibase, "
951 "obase, last, var, or array element",
952 "no auto variable found",
953 "function parameter or auto var has the same name as another",
954 "block end could not be found",
957 "non integer number",
962 "could not open file:",
963 "mismatched parameters",
964 "undefined function",
965 "file is not executable:",
966 "number too long: must be [1, BC_NUM_MAX]",
967 "name too long: must be [1, BC_NAME_MAX]",
968 "string too long: must be [1, BC_STRING_MAX]",
969 "array too long; must be [1, BC_DIM_MAX]",
970 "bad ibase; must be [2, 16]",
971 "bad scale; must be [0, BC_SCALE_MAX]",
972 "bad read() expression",
973 "read() call inside of a read() call",
974 "variable is wrong type",
975 "bad obase; must be [2, BC_BASE_MAX]",
976 "signal caught and not handled",
977 "stack has too few elements",
979 "index is out of bounds",
980 "item already exists",
983 "POSIX only allows one character names; the following is bad:",
984 "POSIX does not allow '#' script comments",
985 "POSIX does not allow the following keyword:",
986 "POSIX does not allow a period ('.') as a shortcut for the last result",
987 "POSIX requires parentheses around return expressions",
988 "POSIX does not allow boolean operators; the following is bad:",
989 "POSIX does not allow comparison operators outside if or loops",
990 "POSIX requires exactly one comparison operator per condition",
991 "POSIX does not allow an empty init expression in a for loop",
992 "POSIX does not allow an empty condition expression in a for loop",
993 "POSIX does not allow an empty update expression in a for loop",
994 "POSIX requires the left brace be on the same line as the function header",
999 static const char bc_func_main[] = "(main)";
1000 static const char bc_func_read[] = "(read)";
1003 static const BcLexKeyword bc_lex_kws[20] = {
1004 BC_LEX_KW_ENTRY("auto", 4, true),
1005 BC_LEX_KW_ENTRY("break", 5, true),
1006 BC_LEX_KW_ENTRY("continue", 8, false),
1007 BC_LEX_KW_ENTRY("define", 6, true),
1008 BC_LEX_KW_ENTRY("else", 4, false),
1009 BC_LEX_KW_ENTRY("for", 3, true),
1010 BC_LEX_KW_ENTRY("halt", 4, false),
1011 BC_LEX_KW_ENTRY("ibase", 5, true),
1012 BC_LEX_KW_ENTRY("if", 2, true),
1013 BC_LEX_KW_ENTRY("last", 4, false),
1014 BC_LEX_KW_ENTRY("length", 6, true),
1015 BC_LEX_KW_ENTRY("limits", 6, false),
1016 BC_LEX_KW_ENTRY("obase", 5, true),
1017 BC_LEX_KW_ENTRY("print", 5, false),
1018 BC_LEX_KW_ENTRY("quit", 4, true),
1019 BC_LEX_KW_ENTRY("read", 4, false),
1020 BC_LEX_KW_ENTRY("return", 6, true),
1021 BC_LEX_KW_ENTRY("scale", 5, true),
1022 BC_LEX_KW_ENTRY("sqrt", 4, true),
1023 BC_LEX_KW_ENTRY("while", 5, true),
1026 // This is an array that corresponds to token types. An entry is
1027 // true if the token is valid in an expression, false otherwise.
1028 static const bool bc_parse_exprs[] = {
1029 false, false, true, true, true, true, true, true, true, true, true, true,
1030 true, true, true, true, true, true, true, true, true, true, true, true,
1031 true, true, true, false, false, true, true, false, false, false, false,
1032 false, false, false, true, true, false, false, false, false, false, false,
1033 false, true, false, true, true, true, true, false, false, true, false, true,
1037 // This is an array of data for operators that correspond to token types.
1038 static const BcOp bc_parse_ops[] = {
1039 { 0, false }, { 0, false },
1042 { 3, true }, { 3, true }, { 3, true },
1043 { 4, true }, { 4, true },
1044 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1046 { 7, true }, { 7, true },
1047 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1048 { 5, false }, { 5, false },
1051 // These identify what tokens can come after expressions in certain cases.
1052 static const BcParseNext bc_parse_next_expr =
1053 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1054 static const BcParseNext bc_parse_next_param =
1055 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1056 static const BcParseNext bc_parse_next_print =
1057 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1058 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1059 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1060 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1061 static const BcParseNext bc_parse_next_read =
1062 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1066 static const BcLexType dc_lex_regs[] = {
1067 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1068 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1069 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1073 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1075 static const BcLexType dc_lex_tokens[] = {
1076 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1077 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1078 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1079 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1080 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1081 BC_LEX_INVALID, BC_LEX_INVALID,
1082 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1083 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1084 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1085 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1086 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1087 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1088 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1089 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1090 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1091 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1092 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1093 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1094 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1095 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1096 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1097 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1098 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1099 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1103 static const BcInst dc_parse_insts[] = {
1104 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1105 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1106 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1107 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1108 BC_INST_INVALID, BC_INST_INVALID,
1109 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1110 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1111 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1112 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1113 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1114 BC_INST_INVALID, BC_INST_INVALID,
1115 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1116 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1117 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1118 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1119 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1120 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1121 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1122 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1123 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1124 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1125 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1126 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1130 static const BcNumBinaryOp bc_program_ops[] = {
1131 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1134 static const char bc_program_stdin_name[] = "<stdin>";
1135 static const char bc_program_ready_msg[] = "ready for more input\n";
1138 static const char *bc_lib_name = "gen/lib.bc";
1140 static const char bc_lib[] = {
1141 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1142 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1143 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1144 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,
1145 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1146 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1147 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,
1148 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1149 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1150 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,
1151 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1152 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1153 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1154 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1155 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1156 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1157 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1158 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1159 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1160 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1161 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1162 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1163 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1164 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,
1165 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1166 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,
1167 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1168 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1169 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1170 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1171 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1172 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,
1173 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1174 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1175 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1176 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1177 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,
1178 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1179 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1180 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1181 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1182 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1183 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1184 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1185 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1186 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1187 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1188 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,
1189 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,
1190 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1191 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,
1192 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,
1193 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,
1194 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1195 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1196 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,
1197 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,
1198 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,
1199 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1200 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,
1201 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1202 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1203 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1204 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,
1205 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1206 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1207 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1208 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1209 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1210 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1211 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1212 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1213 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1214 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1215 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1216 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1217 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1218 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1219 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1220 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1224 static void bc_vec_grow(BcVec *v, size_t n)
1226 size_t cap = v->cap * 2;
1227 while (cap < v->len + n) cap *= 2;
1228 v->v = xrealloc(v->v, v->size * cap);
1232 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1235 v->cap = BC_VEC_START_CAP;
1238 v->v = xmalloc(esize * BC_VEC_START_CAP);
1241 static void bc_vec_expand(BcVec *v, size_t req)
1244 v->v = xrealloc(v->v, v->size * req);
1249 static void bc_vec_npop(BcVec *v, size_t n)
1254 size_t len = v->len - n;
1255 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1259 static void bc_vec_push(BcVec *v, const void *data)
1261 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1262 memmove(v->v + (v->size * v->len), data, v->size);
1266 static void bc_vec_pushByte(BcVec *v, char data)
1268 bc_vec_push(v, &data);
1271 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1274 bc_vec_push(v, data);
1279 if (v->len == v->cap) bc_vec_grow(v, 1);
1281 ptr = v->v + v->size * idx;
1283 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1284 memmove(ptr, data, v->size);
1288 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1290 bc_vec_npop(v, v->len);
1291 bc_vec_expand(v, len + 1);
1292 memcpy(v->v, str, len);
1295 bc_vec_pushByte(v, '\0');
1298 static void bc_vec_concat(BcVec *v, const char *str)
1302 if (v->len == 0) bc_vec_pushByte(v, '\0');
1304 len = v->len + strlen(str);
1306 if (v->cap < len) bc_vec_grow(v, len - v->len);
1312 static void *bc_vec_item(const BcVec *v, size_t idx)
1314 return v->v + v->size * idx;
1317 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1319 return v->v + v->size * (v->len - idx - 1);
1322 static void bc_vec_free(void *vec)
1324 BcVec *v = (BcVec *) vec;
1325 bc_vec_npop(v, v->len);
1329 static size_t bc_map_find(const BcVec *v, const void *ptr)
1331 size_t low = 0, high = v->len;
1333 while (low < high) {
1335 size_t mid = (low + high) / 2;
1336 BcId *id = bc_vec_item(v, mid);
1337 int result = bc_id_cmp(ptr, id);
1341 else if (result < 0)
1350 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1352 BcStatus s = BC_STATUS_SUCCESS;
1354 *i = bc_map_find(v, ptr);
1357 bc_vec_push(v, ptr);
1358 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1359 s = BC_STATUS_VEC_ITEM_EXISTS;
1361 bc_vec_pushAt(v, ptr, *i);
1366 static size_t bc_map_index(const BcVec *v, const void *ptr)
1368 size_t i = bc_map_find(v, ptr);
1369 if (i >= v->len) return BC_VEC_INVALID_IDX;
1370 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1373 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1378 if (bcg.ttyin && !bcg.posix) {
1379 fputs(prompt, stderr);
1383 bc_vec_npop(vec, vec->len);
1386 if (ferror(stdout) || ferror(stderr))
1387 bb_perror_msg_and_die("output error");
1391 bb_perror_msg_and_die("input error");
1395 #if ENABLE_FEATURE_BC_SIGNALS
1396 if (errno == EINTR) {
1402 fputs(bc_program_ready_msg, stderr);
1403 if (!bcg.posix) fputs(prompt, stderr);
1411 return BC_STATUS_INPUT_EOF;
1414 c = (signed char) i;
1415 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1416 bc_vec_push(vec, &c);
1417 } while (c != '\n');
1419 bc_vec_pushByte(vec, '\0');
1421 return BC_STATUS_SUCCESS;
1424 static BcStatus bc_read_file(const char *path, char **buf)
1426 BcStatus s = BC_STATUS_BIN_FILE;
1427 size_t size = ((size_t) -1);
1430 *buf = xmalloc_open_read_close(path, &size);
1432 for (i = 0; i < size; ++i) {
1433 if (BC_READ_BIN_CHAR((*buf)[i]))
1437 return BC_STATUS_SUCCESS;
1444 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1445 static const char bc_args_lopt[] ALIGN1 =
1446 "extended-register\0"No_argument"x"
1447 "warn\0"No_argument"w"
1448 "version\0"No_argument"v"
1449 "standard\0"No_argument"s"
1450 "quiet\0"No_argument"q"
1451 "mathlib\0"No_argument"l"
1452 "interactive\0"No_argument"i";
1455 static const char bc_args_opt[] ALIGN1 = "xwvsqli";
1457 static BcStatus bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
1459 BcStatus s = BC_STATUS_SUCCESS;
1461 bool do_exit = false;
1465 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1466 *flags = getopt32long(argv, bc_args_opt, bc_args_lopt);
1468 *flags = getopt32(argv, bc_args_opt);
1471 if ((*flags) & BC_FLAG_V) bc_vm_info();
1472 if (do_exit) exit((int) s);
1473 if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1475 for (i = optind; i < argc; ++i) bc_vec_push(files, argv + i);
1480 static void bc_num_setToZero(BcNum *n, size_t scale)
1487 static void bc_num_zero(BcNum *n)
1489 bc_num_setToZero(n, 0);
1492 static void bc_num_one(BcNum *n)
1494 bc_num_setToZero(n, 0);
1499 static void bc_num_ten(BcNum *n)
1501 bc_num_setToZero(n, 0);
1507 static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1511 for (i = 0; !bcg.signe && i < len; ++i) {
1512 for (a[i] -= b[i], j = 0; !bcg.signe && a[i + j] < 0;) {
1517 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1520 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1524 for (i = len - 1; !bcg.signe && i < len && !(c = a[i] - b[i]); --i);
1525 return BC_NUM_NEG(i + 1, c < 0);
1528 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1530 size_t i, min, a_int, b_int, diff;
1531 BcDig *max_num, *min_num;
1532 bool a_max, neg = false;
1535 if (a == b) return 0;
1536 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1537 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1547 a_int = BC_NUM_INT(a);
1548 b_int = BC_NUM_INT(b);
1550 a_max = (a->rdx > b->rdx);
1552 if (a_int != 0) return (ssize_t) a_int;
1556 diff = a->rdx - b->rdx;
1557 max_num = a->num + diff;
1562 diff = b->rdx - a->rdx;
1563 max_num = b->num + diff;
1567 cmp = bc_num_compare(max_num, min_num, b_int + min);
1568 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1570 for (max_num -= diff, i = diff - 1; !bcg.signe && i < diff; --i) {
1571 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1577 static void bc_num_truncate(BcNum *n, size_t places)
1579 if (places == 0) return;
1585 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1589 static void bc_num_extend(BcNum *n, size_t places)
1591 size_t len = n->len + places;
1595 if (n->cap < len) bc_num_expand(n, len);
1597 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1598 memset(n->num, 0, sizeof(BcDig) * places);
1605 static void bc_num_clean(BcNum *n)
1607 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1610 else if (n->len < n->rdx)
1614 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1617 bc_num_extend(n, scale - n->rdx);
1619 bc_num_truncate(n, n->rdx - scale);
1622 if (n->len != 0) n->neg = !neg1 != !neg2;
1625 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1630 b->len = n->len - idx;
1632 a->rdx = b->rdx = 0;
1634 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1635 memcpy(a->num, n->num, idx * sizeof(BcDig));
1646 static BcStatus bc_num_shift(BcNum *n, size_t places)
1648 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1649 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1651 if (n->rdx >= places)
1654 bc_num_extend(n, places - n->rdx);
1660 return BC_STATUS_SUCCESS;
1663 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1672 return bc_num_div(&one, a, b, scale);
1675 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1677 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1678 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1681 // Because this function doesn't need to use scale (per the bc spec),
1682 // I am hijacking it to say whether it's doing an add or a subtract.
1686 if (sub && c->len) c->neg = !c->neg;
1687 return BC_STATUS_SUCCESS;
1689 else if (b->len == 0) {
1691 return BC_STATUS_SUCCESS;
1695 c->rdx = BC_MAX(a->rdx, b->rdx);
1696 min_rdx = BC_MIN(a->rdx, b->rdx);
1699 if (a->rdx > b->rdx) {
1700 diff = a->rdx - b->rdx;
1702 ptr_a = a->num + diff;
1706 diff = b->rdx - a->rdx;
1709 ptr_b = b->num + diff;
1712 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1715 a_int = BC_NUM_INT(a);
1716 b_int = BC_NUM_INT(b);
1718 if (a_int > b_int) {
1729 for (carry = 0, i = 0; !bcg.signe && i < min_rdx + min_int; ++i, ++c->len) {
1730 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1732 ptr_c[i] = (BcDig)(in % 10);
1735 for (; !bcg.signe && i < max + min_rdx; ++i, ++c->len) {
1736 in = ((int) ptr[i]) + carry;
1738 ptr_c[i] = (BcDig)(in % 10);
1741 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1743 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1746 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1750 BcNum *minuend, *subtrahend;
1752 bool aneg, bneg, neg;
1754 // Because this function doesn't need to use scale (per the bc spec),
1755 // I am hijacking it to say whether it's doing an add or a subtract.
1759 if (sub && c->len) c->neg = !c->neg;
1760 return BC_STATUS_SUCCESS;
1762 else if (b->len == 0) {
1764 return BC_STATUS_SUCCESS;
1769 a->neg = b->neg = false;
1771 cmp = bc_num_cmp(a, b);
1777 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1778 return BC_STATUS_SUCCESS;
1787 if (sub) neg = !neg;
1792 bc_num_copy(c, minuend);
1795 if (c->rdx < subtrahend->rdx) {
1796 bc_num_extend(c, subtrahend->rdx - c->rdx);
1800 start = c->rdx - subtrahend->rdx;
1802 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1809 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1814 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1815 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1816 bool aone = BC_NUM_ONE(a);
1818 if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
1819 if (a->len == 0 || b->len == 0) {
1821 return BC_STATUS_SUCCESS;
1823 else if (aone || BC_NUM_ONE(b)) {
1824 bc_num_copy(c, aone ? b : a);
1825 return BC_STATUS_SUCCESS;
1828 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1829 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1831 bc_num_expand(c, a->len + b->len + 1);
1833 memset(c->num, 0, sizeof(BcDig) * c->cap);
1834 c->len = carry = len = 0;
1836 for (i = 0; !bcg.signe && i < b->len; ++i) {
1838 for (j = 0; !bcg.signe && j < a->len; ++j) {
1839 int in = (int) c->num[i + j];
1840 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1842 c->num[i + j] = (BcDig)(in % 10);
1845 c->num[i + j] += (BcDig) carry;
1846 len = BC_MAX(len, i + j + !!carry);
1852 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1855 bc_num_init(&l1, max);
1856 bc_num_init(&h1, max);
1857 bc_num_init(&l2, max);
1858 bc_num_init(&h2, max);
1859 bc_num_init(&m1, max);
1860 bc_num_init(&m2, max);
1861 bc_num_init(&z0, max);
1862 bc_num_init(&z1, max);
1863 bc_num_init(&z2, max);
1864 bc_num_init(&temp, max + max);
1866 bc_num_split(a, max2, &l1, &h1);
1867 bc_num_split(b, max2, &l2, &h2);
1869 s = bc_num_add(&h1, &l1, &m1, 0);
1871 s = bc_num_add(&h2, &l2, &m2, 0);
1874 s = bc_num_k(&h1, &h2, &z0);
1876 s = bc_num_k(&m1, &m2, &z1);
1878 s = bc_num_k(&l1, &l2, &z2);
1881 s = bc_num_sub(&z1, &z0, &temp, 0);
1883 s = bc_num_sub(&temp, &z2, &z1, 0);
1886 s = bc_num_shift(&z0, max2 * 2);
1888 s = bc_num_shift(&z1, max2);
1890 s = bc_num_add(&z0, &z1, &temp, 0);
1892 s = bc_num_add(&temp, &z2, c, 0);
1908 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1912 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1914 scale = BC_MAX(scale, a->rdx);
1915 scale = BC_MAX(scale, b->rdx);
1916 scale = BC_MIN(a->rdx + b->rdx, scale);
1917 maxrdx = BC_MAX(maxrdx, scale);
1919 bc_num_init(&cpa, a->len);
1920 bc_num_init(&cpb, b->len);
1922 bc_num_copy(&cpa, a);
1923 bc_num_copy(&cpb, b);
1924 cpa.neg = cpb.neg = false;
1926 s = bc_num_shift(&cpa, maxrdx);
1928 s = bc_num_shift(&cpb, maxrdx);
1930 s = bc_num_k(&cpa, &cpb, c);
1934 bc_num_expand(c, c->len + maxrdx);
1936 if (c->len < maxrdx) {
1937 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1942 bc_num_retireMul(c, scale, a->neg, b->neg);
1950 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1952 BcStatus s = BC_STATUS_SUCCESS;
1959 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1960 else if (a->len == 0) {
1961 bc_num_setToZero(c, scale);
1962 return BC_STATUS_SUCCESS;
1964 else if (BC_NUM_ONE(b)) {
1966 bc_num_retireMul(c, scale, a->neg, b->neg);
1967 return BC_STATUS_SUCCESS;
1970 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1971 bc_num_copy(&cp, a);
1975 bc_num_expand(&cp, len + 2);
1976 bc_num_extend(&cp, len - cp.len);
1979 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1981 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1983 if (b->rdx == b->len) {
1984 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1988 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1990 // We want an extra zero in front to make things simpler.
1991 cp.num[cp.len++] = 0;
1994 bc_num_expand(c, cp.len);
1997 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
2002 for (i = end - 1; !bcg.signe && !s && i < end; --i) {
2004 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
2005 s = bc_num_subArrays(n, p, len);
2009 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
2015 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
2016 BcNum *restrict d, size_t scale, size_t ts)
2022 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2025 bc_num_setToZero(d, ts);
2026 return BC_STATUS_SUCCESS;
2029 bc_num_init(&temp, d->cap);
2030 bc_num_d(a, b, c, scale);
2032 if (scale != 0) scale = ts;
2034 s = bc_num_m(c, b, &temp, scale);
2036 s = bc_num_sub(a, &temp, d, scale);
2039 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2042 bc_num_retireMul(d, ts, a->neg, b->neg);
2050 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2054 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2056 bc_num_init(&c1, len);
2057 s = bc_num_r(a, b, &c1, c, scale, ts);
2063 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2065 BcStatus s = BC_STATUS_SUCCESS;
2068 size_t i, powrdx, resrdx;
2071 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2075 return BC_STATUS_SUCCESS;
2077 else if (a->len == 0) {
2078 bc_num_setToZero(c, scale);
2079 return BC_STATUS_SUCCESS;
2081 else if (BC_NUM_ONE(b)) {
2085 s = bc_num_inv(a, c, scale);
2092 s = bc_num_ulong(b, &pow);
2095 bc_num_init(©, a->len);
2096 bc_num_copy(©, a);
2098 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2102 for (powrdx = a->rdx; !bcg.signe && !(pow & 1); pow >>= 1) {
2104 s = bc_num_mul(©, ©, ©, powrdx);
2109 s = BC_STATUS_EXEC_SIGNAL;
2113 bc_num_copy(c, ©);
2115 for (resrdx = powrdx, pow >>= 1; !bcg.signe && pow != 0; pow >>= 1) {
2118 s = bc_num_mul(©, ©, ©, powrdx);
2123 s = bc_num_mul(c, ©, c, resrdx);
2129 s = bc_num_inv(c, c, scale);
2134 s = BC_STATUS_EXEC_SIGNAL;
2138 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2140 // We can't use bc_num_clean() here.
2141 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2142 if (zero) bc_num_setToZero(c, scale);
2149 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2150 BcNumBinaryOp op, size_t req)
2153 BcNum num2, *ptr_a, *ptr_b;
2158 memcpy(ptr_a, c, sizeof(BcNum));
2167 memcpy(ptr_b, c, sizeof(BcNum));
2175 bc_num_init(c, req);
2177 bc_num_expand(c, req);
2179 s = op(ptr_a, ptr_b, c, scale);
2181 if (init) bc_num_free(&num2);
2186 static bool bc_num_strValid(const char *val, size_t base)
2189 bool small, radix = false;
2190 size_t i, len = strlen(val);
2192 if (!len) return true;
2195 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2197 for (i = 0; i < len; ++i) {
2203 if (radix) return false;
2209 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2216 static void bc_num_parseDecimal(BcNum *n, const char *val)
2222 for (i = 0; val[i] == '0'; ++i);
2229 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2230 bc_num_expand(n, len);
2233 ptr = strchr(val, '.');
2235 // Explicitly test for NULL here to produce either a 0 or 1.
2236 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2239 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2240 n->num[n->len] = val[i] - '0';
2244 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2247 BcNum temp, mult, result;
2251 size_t i, digits, len = strlen(val);
2255 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2258 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2259 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2261 for (i = 0; i < len; ++i) {
2264 if (c == '.') break;
2266 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2268 s = bc_num_mul(n, base, &mult, 0);
2269 if (s) goto int_err;
2270 s = bc_num_ulong2num(&temp, v);
2271 if (s) goto int_err;
2272 s = bc_num_add(&mult, &temp, n, 0);
2273 if (s) goto int_err;
2278 if (c == 0) goto int_err;
2281 bc_num_init(&result, base->len);
2282 bc_num_zero(&result);
2285 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2290 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2292 s = bc_num_mul(&result, base, &result, 0);
2294 s = bc_num_ulong2num(&temp, v);
2296 s = bc_num_add(&result, &temp, &result, 0);
2298 s = bc_num_mul(&mult, base, &mult, 0);
2302 s = bc_num_div(&result, &mult, &result, digits);
2304 s = bc_num_add(n, &result, n, digits);
2308 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2314 bc_num_free(&result);
2320 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2322 if (*nchars == line_len - 1) {
2330 static void bc_num_printChar(size_t num, size_t width, bool radix,
2331 size_t *nchars, size_t line_len)
2333 (void) radix, (void) line_len;
2334 bb_putchar((char) num);
2335 *nchars = *nchars + width;
2339 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2340 size_t *nchars, size_t line_len)
2344 bc_num_printNewline(nchars, line_len);
2345 bb_putchar(radix ? '.' : ' ');
2348 bc_num_printNewline(nchars, line_len);
2349 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2352 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2354 bc_num_printNewline(nchars, line_len);
2357 bb_putchar(((char) dig) + '0');
2361 static void bc_num_printHex(size_t num, size_t width, bool radix,
2362 size_t *nchars, size_t line_len)
2365 bc_num_printNewline(nchars, line_len);
2370 bc_num_printNewline(nchars, line_len);
2371 bb_putchar(bb_hexdigits_upcase[num]);
2372 *nchars = *nchars + width;
2375 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2377 size_t i, rdx = n->rdx - 1;
2379 if (n->neg) bb_putchar('-');
2380 (*nchars) += n->neg;
2382 for (i = n->len - 1; i < n->len; --i)
2383 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2386 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2387 size_t *nchars, size_t len, BcNumDigitOp print)
2391 BcNum intp, fracp, digit, frac_len;
2392 unsigned long dig, *ptr;
2397 print(0, width, false, nchars, len);
2398 return BC_STATUS_SUCCESS;
2401 bc_vec_init(&stack, sizeof(long), NULL);
2402 bc_num_init(&intp, n->len);
2403 bc_num_init(&fracp, n->rdx);
2404 bc_num_init(&digit, width);
2405 bc_num_init(&frac_len, BC_NUM_INT(n));
2406 bc_num_copy(&intp, n);
2407 bc_num_one(&frac_len);
2409 bc_num_truncate(&intp, intp.rdx);
2410 s = bc_num_sub(n, &intp, &fracp, 0);
2413 while (intp.len != 0) {
2414 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2416 s = bc_num_ulong(&digit, &dig);
2418 bc_vec_push(&stack, &dig);
2421 for (i = 0; i < stack.len; ++i) {
2422 ptr = bc_vec_item_rev(&stack, i);
2423 print(*ptr, width, false, nchars, len);
2426 if (!n->rdx) goto err;
2428 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2429 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2431 s = bc_num_ulong(&fracp, &dig);
2433 s = bc_num_ulong2num(&intp, dig);
2435 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2437 print(dig, width, radix, nchars, len);
2438 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2443 bc_num_free(&frac_len);
2444 bc_num_free(&digit);
2445 bc_num_free(&fracp);
2447 bc_vec_free(&stack);
2451 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2452 size_t *nchars, size_t line_len)
2459 if (neg) bb_putchar('-');
2464 if (base_t <= BC_NUM_MAX_IBASE) {
2466 print = bc_num_printHex;
2469 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2470 print = bc_num_printDigits;
2473 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2480 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2482 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2486 static void bc_num_init(BcNum *n, size_t req)
2488 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2489 memset(n, 0, sizeof(BcNum));
2490 n->num = xmalloc(req);
2494 static void bc_num_expand(BcNum *n, size_t req)
2496 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2498 n->num = xrealloc(n->num, req);
2503 static void bc_num_free(void *num)
2505 free(((BcNum *) num)->num);
2508 static void bc_num_copy(BcNum *d, BcNum *s)
2511 bc_num_expand(d, s->cap);
2515 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2519 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2522 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2525 bc_num_parseDecimal(n, val);
2527 bc_num_parseBase(n, val, base);
2529 return BC_STATUS_SUCCESS;
2532 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2533 size_t *nchars, size_t line_len)
2535 BcStatus s = BC_STATUS_SUCCESS;
2537 bc_num_printNewline(nchars, line_len);
2543 else if (base_t == 10)
2544 bc_num_printDecimal(n, nchars, line_len);
2546 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2556 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2561 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2563 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2565 unsigned long prev = *result, powprev = pow;
2567 *result += ((unsigned long) n->num[i]) * pow;
2570 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2573 return BC_STATUS_SUCCESS;
2576 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val)
2584 if (val == 0) return BC_STATUS_SUCCESS;
2586 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2587 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2589 return BC_STATUS_SUCCESS;
2592 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2594 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2596 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2599 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2601 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2603 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2606 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2608 size_t req = BC_NUM_MREQ(a, b, scale);
2609 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2612 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2614 size_t req = BC_NUM_MREQ(a, b, scale);
2615 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2618 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2620 size_t req = BC_NUM_MREQ(a, b, scale);
2621 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2624 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2626 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2629 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2632 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2633 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2634 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2636 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2637 bc_num_expand(b, req);
2640 bc_num_setToZero(b, scale);
2641 return BC_STATUS_SUCCESS;
2644 return BC_STATUS_MATH_NEGATIVE;
2645 else if (BC_NUM_ONE(a)) {
2647 bc_num_extend(b, scale);
2648 return BC_STATUS_SUCCESS;
2651 scale = BC_MAX(scale, a->rdx) + 1;
2652 len = a->len + scale;
2654 bc_num_init(&num1, len);
2655 bc_num_init(&num2, len);
2656 bc_num_init(&half, BC_NUM_DEF_SIZE);
2662 bc_num_init(&f, len);
2663 bc_num_init(&fprime, len);
2669 pow = BC_NUM_INT(a);
2678 pow -= 2 - (pow & 1);
2680 bc_num_extend(x0, pow);
2682 // Make sure to move the radix back.
2686 x0->rdx = digs = digs1 = 0;
2688 len = BC_NUM_INT(x0) + resrdx - 1;
2690 while (!bcg.signe && (cmp != 0 || digs < len)) {
2692 s = bc_num_div(a, x0, &f, resrdx);
2694 s = bc_num_add(x0, &f, &fprime, resrdx);
2696 s = bc_num_mul(&fprime, &half, x1, resrdx);
2699 cmp = bc_num_cmp(x1, x0);
2700 digs = x1->len - (unsigned long long) llabs(cmp);
2702 if (cmp == cmp2 && digs == digs1)
2707 resrdx += times > 4;
2719 s = BC_STATUS_EXEC_SIGNAL;
2725 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2728 bc_num_free(&fprime);
2736 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2742 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2745 memcpy(&num2, c, sizeof(BcNum));
2747 bc_num_init(c, len);
2752 bc_num_expand(c, len);
2755 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2757 if (init) bc_num_free(&num2);
2763 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2766 BcNum base, exp, two, temp;
2768 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2769 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2770 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2772 bc_num_expand(d, c->len);
2773 bc_num_init(&base, c->len);
2774 bc_num_init(&exp, b->len);
2775 bc_num_init(&two, BC_NUM_DEF_SIZE);
2776 bc_num_init(&temp, b->len);
2782 s = bc_num_rem(a, c, &base, 0);
2784 bc_num_copy(&exp, b);
2786 while (exp.len != 0) {
2788 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2791 if (BC_NUM_ONE(&temp)) {
2792 s = bc_num_mul(d, &base, &temp, 0);
2794 s = bc_num_rem(&temp, c, d, 0);
2798 s = bc_num_mul(&base, &base, &temp, 0);
2800 s = bc_num_rem(&temp, c, &base, 0);
2813 static int bc_id_cmp(const void *e1, const void *e2)
2815 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2818 static void bc_id_free(void *id)
2820 free(((BcId *) id)->name);
2823 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2828 for (i = 0; i < f->autos.len; ++i) {
2829 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2830 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2836 bc_vec_push(&f->autos, &a);
2838 return BC_STATUS_SUCCESS;
2841 static void bc_func_init(BcFunc *f)
2843 bc_vec_init(&f->code, sizeof(char), NULL);
2844 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2845 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2849 static void bc_func_free(void *func)
2851 BcFunc *f = (BcFunc *) func;
2852 bc_vec_free(&f->code);
2853 bc_vec_free(&f->autos);
2854 bc_vec_free(&f->labels);
2857 static void bc_array_init(BcVec *a, bool nums)
2860 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2862 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2863 bc_array_expand(a, 1);
2866 static void bc_array_copy(BcVec *d, const BcVec *s)
2870 bc_vec_npop(d, d->len);
2871 bc_vec_expand(d, s->cap);
2874 for (i = 0; i < s->len; ++i) {
2875 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2876 bc_num_init(dnum, snum->len);
2877 bc_num_copy(dnum, snum);
2881 static void bc_array_expand(BcVec *a, size_t len)
2885 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2886 while (len > a->len) {
2887 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2888 bc_vec_push(a, &data.n);
2892 while (len > a->len) {
2893 bc_array_init(&data.v, true);
2894 bc_vec_push(a, &data.v);
2899 static void bc_string_free(void *string)
2901 free(*((char **) string));
2905 static void bc_result_copy(BcResult *d, BcResult *src)
2911 case BC_RESULT_TEMP:
2912 case BC_RESULT_IBASE:
2913 case BC_RESULT_SCALE:
2914 case BC_RESULT_OBASE:
2916 bc_num_init(&d->d.n, src->d.n.len);
2917 bc_num_copy(&d->d.n, &src->d.n);
2922 case BC_RESULT_ARRAY:
2923 case BC_RESULT_ARRAY_ELEM:
2925 d->d.id.name = xstrdup(src->d.id.name);
2929 case BC_RESULT_CONSTANT:
2930 case BC_RESULT_LAST:
2934 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2941 static void bc_result_free(void *result)
2943 BcResult *r = (BcResult *) result;
2947 case BC_RESULT_TEMP:
2948 case BC_RESULT_IBASE:
2949 case BC_RESULT_SCALE:
2950 case BC_RESULT_OBASE:
2952 bc_num_free(&r->d.n);
2957 case BC_RESULT_ARRAY:
2958 case BC_RESULT_ARRAY_ELEM:
2972 static void bc_lex_lineComment(BcLex *l)
2974 l->t.t = BC_LEX_WHITESPACE;
2975 while (l->i < l->len && l->buf[l->i++] != '\n');
2979 static void bc_lex_whitespace(BcLex *l)
2982 l->t.t = BC_LEX_WHITESPACE;
2983 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2986 static BcStatus bc_lex_number(BcLex *l, char start)
2988 const char *buf = l->buf + l->i;
2989 size_t len, hits = 0, bslashes = 0, i = 0, j;
2991 bool last_pt, pt = start == '.';
2994 l->t.t = BC_LEX_NUMBER;
2996 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2997 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
3011 len = i + 1 * !last_pt - bslashes * 2;
3012 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
3014 bc_vec_npop(&l->t.v, l->t.v.len);
3015 bc_vec_expand(&l->t.v, len + 1);
3016 bc_vec_push(&l->t.v, &start);
3018 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
3022 // If we have hit a backslash, skip it. We don't have
3023 // to check for a newline because it's guaranteed.
3024 if (hits < bslashes && c == '\\') {
3030 bc_vec_push(&l->t.v, &c);
3033 bc_vec_pushByte(&l->t.v, '\0');
3036 return BC_STATUS_SUCCESS;
3039 static BcStatus bc_lex_name(BcLex *l)
3042 const char *buf = l->buf + l->i - 1;
3045 l->t.t = BC_LEX_NAME;
3047 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3049 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3050 bc_vec_string(&l->t.v, i, buf);
3052 // Increment the index. We minus 1 because it has already been incremented.
3055 return BC_STATUS_SUCCESS;
3058 static void bc_lex_init(BcLex *l, BcLexNext next)
3061 bc_vec_init(&l->t.v, sizeof(char), NULL);
3064 static void bc_lex_free(BcLex *l)
3066 bc_vec_free(&l->t.v);
3069 static void bc_lex_file(BcLex *l, const char *file)
3076 static BcStatus bc_lex_next(BcLex *l)
3081 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3083 l->line += l->newline;
3084 l->t.t = BC_LEX_EOF;
3086 l->newline = (l->i == l->len);
3087 if (l->newline) return BC_STATUS_SUCCESS;
3089 // Loop until failure or we don't have whitespace. This
3090 // is so the parser doesn't get inundated with whitespace.
3093 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3098 static BcStatus bc_lex_text(BcLex *l, const char *text)
3102 l->len = strlen(text);
3103 l->t.t = l->t.last = BC_LEX_INVALID;
3104 return bc_lex_next(l);
3108 static BcStatus bc_lex_identifier(BcLex *l)
3112 const char *buf = l->buf + l->i - 1;
3114 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3116 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3118 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3120 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3122 if (!bc_lex_kws[i].posix) {
3123 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3124 bc_lex_kws[i].name);
3128 // We minus 1 because the index has already been incremented.
3130 return BC_STATUS_SUCCESS;
3137 if (l->t.v.len - 1 > 1)
3138 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3143 static BcStatus bc_lex_string(BcLex *l)
3145 size_t len, nls = 0, i = l->i;
3148 l->t.t = BC_LEX_STR;
3150 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3154 return BC_STATUS_LEX_NO_STRING_END;
3158 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3159 bc_vec_string(&l->t.v, len, l->buf + l->i);
3164 return BC_STATUS_SUCCESS;
3167 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3169 if (l->buf[l->i] == '=') {
3177 static BcStatus bc_lex_comment(BcLex *l)
3180 const char *buf = l->buf;
3184 l->t.t = BC_LEX_WHITESPACE;
3186 for (i = ++l->i; !end; i += !end) {
3188 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3190 if (c == 0 || buf[i + 1] == '\0') {
3192 return BC_STATUS_LEX_NO_COMMENT_END;
3195 end = buf[i + 1] == '/';
3201 return BC_STATUS_SUCCESS;
3204 static BcStatus bc_lex_token(BcLex *l)
3206 BcStatus s = BC_STATUS_SUCCESS;
3207 char c = l->buf[l->i++], c2;
3209 // This is the workhorse of the lexer.
3216 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3226 bc_lex_whitespace(l);
3232 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3234 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3235 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3244 s = bc_lex_string(l);
3250 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3253 bc_lex_lineComment(l);
3260 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3269 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3273 l->t.t = BC_LEX_OP_BOOL_AND;
3276 l->t.t = BC_LEX_INVALID;
3277 s = BC_STATUS_LEX_BAD_CHAR;
3286 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3292 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3301 l->t.t = BC_LEX_OP_INC;
3304 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3310 l->t.t = BC_LEX_COMMA;
3319 l->t.t = BC_LEX_OP_DEC;
3322 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3328 if (isdigit(l->buf[l->i]))
3329 s = bc_lex_number(l, c);
3331 l->t.t = BC_LEX_KEY_LAST;
3332 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3341 s = bc_lex_comment(l);
3343 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3364 s = bc_lex_number(l, c);
3370 l->t.t = BC_LEX_SCOLON;
3376 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3382 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3388 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3395 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3401 if (l->buf[l->i] == '\n') {
3402 l->t.t = BC_LEX_WHITESPACE;
3406 s = BC_STATUS_LEX_BAD_CHAR;
3412 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3443 s = bc_lex_identifier(l);
3450 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3460 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3464 l->t.t = BC_LEX_OP_BOOL_OR;
3467 l->t.t = BC_LEX_INVALID;
3468 s = BC_STATUS_LEX_BAD_CHAR;
3476 l->t.t = BC_LEX_INVALID;
3477 s = BC_STATUS_LEX_BAD_CHAR;
3487 static BcStatus dc_lex_register(BcLex *l)
3489 BcStatus s = BC_STATUS_SUCCESS;
3491 if (isspace(l->buf[l->i - 1])) {
3492 bc_lex_whitespace(l);
3495 s = BC_STATUS_LEX_EXTENDED_REG;
3500 bc_vec_npop(&l->t.v, l->t.v.len);
3501 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3502 bc_vec_pushByte(&l->t.v, '\0');
3503 l->t.t = BC_LEX_NAME;
3509 static BcStatus dc_lex_string(BcLex *l)
3511 size_t depth = 1, nls = 0, i = l->i;
3514 l->t.t = BC_LEX_STR;
3515 bc_vec_npop(&l->t.v, l->t.v.len);
3517 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3519 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3520 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3523 if (depth) bc_vec_push(&l->t.v, &c);
3528 return BC_STATUS_LEX_NO_STRING_END;
3531 bc_vec_pushByte(&l->t.v, '\0');
3532 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3537 return BC_STATUS_SUCCESS;
3540 static BcStatus dc_lex_token(BcLex *l)
3542 BcStatus s = BC_STATUS_SUCCESS;
3543 char c = l->buf[l->i++], c2;
3546 for (i = 0; i < dc_lex_regs_len; ++i) {
3547 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3550 if (c >= '%' && c <= '~' &&
3551 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3556 // This is the workhorse of the lexer.
3561 l->t.t = BC_LEX_EOF;
3572 l->newline = (c == '\n');
3573 bc_lex_whitespace(l);
3582 l->t.t = BC_LEX_OP_REL_NE;
3584 l->t.t = BC_LEX_OP_REL_LE;
3586 l->t.t = BC_LEX_OP_REL_GE;
3588 return BC_STATUS_LEX_BAD_CHAR;
3596 bc_lex_lineComment(l);
3602 if (isdigit(l->buf[l->i]))
3603 s = bc_lex_number(l, c);
3605 s = BC_STATUS_LEX_BAD_CHAR;
3626 s = bc_lex_number(l, c);
3632 s = dc_lex_string(l);
3638 l->t.t = BC_LEX_INVALID;
3639 s = BC_STATUS_LEX_BAD_CHAR;
3648 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3650 bc_program_addFunc(p->prog, name, idx);
3651 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3654 static void bc_parse_pushName(BcParse *p, char *name)
3656 size_t i = 0, len = strlen(name);
3658 for (; i < len; ++i) bc_parse_push(p, name[i]);
3659 bc_parse_push(p, BC_PARSE_STREND);
3664 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3666 unsigned char amt, i, nums[sizeof(size_t)];
3668 for (amt = 0; idx; ++amt) {
3669 nums[amt] = (char) idx;
3670 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3673 bc_parse_push(p, amt);
3674 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3677 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3679 char *num = xstrdup(p->l.t.v.v);
3680 size_t idx = p->prog->consts.len;
3682 bc_vec_push(&p->prog->consts, &num);
3684 bc_parse_push(p, BC_INST_NUM);
3685 bc_parse_pushIndex(p, idx);
3688 (*prev) = BC_INST_NUM;
3691 static BcStatus bc_parse_text(BcParse *p, const char *text)
3695 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3697 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3698 p->l.t.t = BC_LEX_INVALID;
3701 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3704 return bc_lex_text(&p->l, text);
3707 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3709 if (p->fidx != BC_PROG_MAIN) {
3711 p->func->nparams = 0;
3712 bc_vec_npop(&p->func->code, p->func->code.len);
3713 bc_vec_npop(&p->func->autos, p->func->autos.len);
3714 bc_vec_npop(&p->func->labels, p->func->labels.len);
3716 bc_parse_updateFunc(p, BC_PROG_MAIN);
3720 p->l.t.t = BC_LEX_EOF;
3721 p->auto_part = (p->nbraces = 0);
3723 bc_vec_npop(&p->flags, p->flags.len - 1);
3724 bc_vec_npop(&p->exits, p->exits.len);
3725 bc_vec_npop(&p->conds, p->conds.len);
3726 bc_vec_npop(&p->ops, p->ops.len);
3728 return bc_program_reset(p->prog, s);
3731 static void bc_parse_free(BcParse *p)
3733 bc_vec_free(&p->flags);
3734 bc_vec_free(&p->exits);
3735 bc_vec_free(&p->conds);
3736 bc_vec_free(&p->ops);
3740 static void bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
3741 BcParseParse parse, BcLexNext next)
3743 memset(p, 0, sizeof(BcParse));
3745 bc_lex_init(&p->l, next);
3746 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3747 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3748 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3749 bc_vec_pushByte(&p->flags, 0);
3750 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3754 p->auto_part = (p->nbraces = 0);
3755 bc_parse_updateFunc(p, func);
3759 static BcStatus bc_parse_else(BcParse *p);
3760 static BcStatus bc_parse_stmt(BcParse *p);
3762 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3763 size_t *nexprs, bool next)
3765 BcStatus s = BC_STATUS_SUCCESS;
3767 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3768 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3770 while (p->ops.len > start) {
3772 t = BC_PARSE_TOP_OP(p);
3773 if (t == BC_LEX_LPAREN) break;
3775 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3776 if (l >= r && (l != r || !left)) break;
3778 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3779 bc_vec_pop(&p->ops);
3780 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3783 bc_vec_push(&p->ops, &type);
3784 if (next) s = bc_lex_next(&p->l);
3789 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3793 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3794 top = BC_PARSE_TOP_OP(p);
3796 while (top != BC_LEX_LPAREN) {
3798 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3800 bc_vec_pop(&p->ops);
3801 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3803 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3804 top = BC_PARSE_TOP_OP(p);
3807 bc_vec_pop(&p->ops);
3809 return bc_lex_next(&p->l);
3812 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3818 s = bc_lex_next(&p->l);
3821 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3823 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3824 s = bc_parse_expr(p, flags, bc_parse_next_param);
3827 comma = p->l.t.t == BC_LEX_COMMA;
3829 s = bc_lex_next(&p->l);
3834 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3835 bc_parse_push(p, BC_INST_CALL);
3836 bc_parse_pushIndex(p, nparams);
3838 return BC_STATUS_SUCCESS;
3841 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3844 BcId entry, *entry_ptr;
3849 s = bc_parse_params(p, flags);
3852 if (p->l.t.t != BC_LEX_RPAREN) {
3853 s = BC_STATUS_PARSE_BAD_TOKEN;
3857 idx = bc_map_index(&p->prog->fn_map, &entry);
3859 if (idx == BC_VEC_INVALID_IDX) {
3860 name = xstrdup(entry.name);
3861 bc_parse_addFunc(p, name, &idx);
3862 idx = bc_map_index(&p->prog->fn_map, &entry);
3868 entry_ptr = bc_vec_item(&p->prog->fn_map, idx);
3869 bc_parse_pushIndex(p, entry_ptr->idx);
3871 return bc_lex_next(&p->l);
3878 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3883 name = xstrdup(p->l.t.v.v);
3884 s = bc_lex_next(&p->l);
3887 if (p->l.t.t == BC_LEX_LBRACKET) {
3889 s = bc_lex_next(&p->l);
3892 if (p->l.t.t == BC_LEX_RBRACKET) {
3894 if (!(flags & BC_PARSE_ARRAY)) {
3895 s = BC_STATUS_PARSE_BAD_EXP;
3899 *type = BC_INST_ARRAY;
3903 *type = BC_INST_ARRAY_ELEM;
3905 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3906 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3910 s = bc_lex_next(&p->l);
3912 bc_parse_push(p, *type);
3913 bc_parse_pushName(p, name);
3915 else if (p->l.t.t == BC_LEX_LPAREN) {
3917 if (flags & BC_PARSE_NOCALL) {
3918 s = BC_STATUS_PARSE_BAD_TOKEN;
3922 *type = BC_INST_CALL;
3923 s = bc_parse_call(p, name, flags);
3926 *type = BC_INST_VAR;
3927 bc_parse_push(p, BC_INST_VAR);
3928 bc_parse_pushName(p, name);
3938 static BcStatus bc_parse_read(BcParse *p)
3942 s = bc_lex_next(&p->l);
3944 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3946 s = bc_lex_next(&p->l);
3948 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3950 bc_parse_push(p, BC_INST_READ);
3952 return bc_lex_next(&p->l);
3955 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3960 s = bc_lex_next(&p->l);
3962 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3964 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3966 s = bc_lex_next(&p->l);
3969 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3972 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3974 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3975 bc_parse_push(p, *prev);
3977 return bc_lex_next(&p->l);
3980 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3984 s = bc_lex_next(&p->l);
3987 if (p->l.t.t != BC_LEX_LPAREN) {
3988 *type = BC_INST_SCALE;
3989 bc_parse_push(p, BC_INST_SCALE);
3990 return BC_STATUS_SUCCESS;
3993 *type = BC_INST_SCALE_FUNC;
3994 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3996 s = bc_lex_next(&p->l);
3999 s = bc_parse_expr(p, flags, bc_parse_next_rel);
4001 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4002 bc_parse_push(p, BC_INST_SCALE_FUNC);
4004 return bc_lex_next(&p->l);
4007 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
4008 size_t *nexprs, uint8_t flags)
4013 BcInst etype = *prev;
4015 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
4016 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
4017 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
4019 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
4020 bc_parse_push(p, inst);
4021 s = bc_lex_next(&p->l);
4025 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
4028 s = bc_lex_next(&p->l);
4032 // Because we parse the next part of the expression
4033 // right here, we need to increment this.
4034 *nexprs = *nexprs + 1;
4040 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4044 case BC_LEX_KEY_IBASE:
4045 case BC_LEX_KEY_LAST:
4046 case BC_LEX_KEY_OBASE:
4048 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4049 s = bc_lex_next(&p->l);
4053 case BC_LEX_KEY_SCALE:
4055 s = bc_lex_next(&p->l);
4057 if (p->l.t.t == BC_LEX_LPAREN)
4058 s = BC_STATUS_PARSE_BAD_TOKEN;
4060 bc_parse_push(p, BC_INST_SCALE);
4066 s = BC_STATUS_PARSE_BAD_TOKEN;
4071 if (!s) bc_parse_push(p, inst);
4077 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4078 bool rparen, size_t *nexprs)
4082 BcInst etype = *prev;
4084 s = bc_lex_next(&p->l);
4087 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4088 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4091 *prev = BC_PARSE_TOKEN_INST(type);
4093 // We can just push onto the op stack because this is the largest
4094 // precedence operator that gets pushed. Inc/dec does not.
4095 if (type != BC_LEX_OP_MINUS)
4096 bc_vec_push(&p->ops, &type);
4098 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4103 static BcStatus bc_parse_string(BcParse *p, char inst)
4105 char *str = xstrdup(p->l.t.v.v);
4107 bc_parse_push(p, BC_INST_STR);
4108 bc_parse_pushIndex(p, p->prog->strs.len);
4109 bc_vec_push(&p->prog->strs, &str);
4110 bc_parse_push(p, inst);
4112 return bc_lex_next(&p->l);
4115 static BcStatus bc_parse_print(BcParse *p)
4121 s = bc_lex_next(&p->l);
4126 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4127 return BC_STATUS_PARSE_BAD_PRINT;
4129 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4131 if (type == BC_LEX_STR)
4132 s = bc_parse_string(p, BC_INST_PRINT_POP);
4134 s = bc_parse_expr(p, 0, bc_parse_next_print);
4136 bc_parse_push(p, BC_INST_PRINT_POP);
4141 comma = p->l.t.t == BC_LEX_COMMA;
4142 if (comma) s = bc_lex_next(&p->l);
4147 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4149 return bc_lex_next(&p->l);
4152 static BcStatus bc_parse_return(BcParse *p)
4158 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4160 s = bc_lex_next(&p->l);
4164 paren = t == BC_LEX_LPAREN;
4166 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4167 bc_parse_push(p, BC_INST_RET0);
4170 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4171 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4173 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4174 bc_parse_push(p, BC_INST_RET0);
4175 s = bc_lex_next(&p->l);
4179 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4180 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4184 bc_parse_push(p, BC_INST_RET);
4190 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4192 BcStatus s = BC_STATUS_SUCCESS;
4194 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4195 return BC_STATUS_PARSE_BAD_TOKEN;
4199 if (p->l.t.t == BC_LEX_RBRACE) {
4200 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4202 s = bc_lex_next(&p->l);
4206 return BC_STATUS_PARSE_BAD_TOKEN;
4209 if (BC_PARSE_IF(p)) {
4213 while (p->l.t.t == BC_LEX_NLINE) {
4214 s = bc_lex_next(&p->l);
4218 bc_vec_pop(&p->flags);
4220 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4221 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4223 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4225 else if (BC_PARSE_ELSE(p)) {
4230 bc_vec_pop(&p->flags);
4232 ip = bc_vec_top(&p->exits);
4233 label = bc_vec_item(&p->func->labels, ip->idx);
4234 *label = p->func->code.len;
4236 bc_vec_pop(&p->exits);
4238 else if (BC_PARSE_FUNC_INNER(p)) {
4239 bc_parse_push(p, BC_INST_RET0);
4240 bc_parse_updateFunc(p, BC_PROG_MAIN);
4241 bc_vec_pop(&p->flags);
4245 BcInstPtr *ip = bc_vec_top(&p->exits);
4246 size_t *label = bc_vec_top(&p->conds);
4248 bc_parse_push(p, BC_INST_JUMP);
4249 bc_parse_pushIndex(p, *label);
4251 label = bc_vec_item(&p->func->labels, ip->idx);
4252 *label = p->func->code.len;
4254 bc_vec_pop(&p->flags);
4255 bc_vec_pop(&p->exits);
4256 bc_vec_pop(&p->conds);
4262 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4264 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4265 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4266 flags |= BC_PARSE_FLAG_BODY;
4267 bc_vec_push(&p->flags, &flags);
4270 static void bc_parse_noElse(BcParse *p)
4274 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4276 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4278 ip = bc_vec_top(&p->exits);
4279 label = bc_vec_item(&p->func->labels, ip->idx);
4280 *label = p->func->code.len;
4282 bc_vec_pop(&p->exits);
4285 static BcStatus bc_parse_if(BcParse *p)
4290 s = bc_lex_next(&p->l);
4292 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4294 s = bc_lex_next(&p->l);
4296 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4298 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4300 s = bc_lex_next(&p->l);
4302 bc_parse_push(p, BC_INST_JUMP_ZERO);
4304 ip.idx = p->func->labels.len;
4305 ip.func = ip.len = 0;
4307 bc_parse_pushIndex(p, ip.idx);
4308 bc_vec_push(&p->exits, &ip);
4309 bc_vec_push(&p->func->labels, &ip.idx);
4310 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4312 return BC_STATUS_SUCCESS;
4315 static BcStatus bc_parse_else(BcParse *p)
4319 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4321 ip.idx = p->func->labels.len;
4322 ip.func = ip.len = 0;
4324 bc_parse_push(p, BC_INST_JUMP);
4325 bc_parse_pushIndex(p, ip.idx);
4329 bc_vec_push(&p->exits, &ip);
4330 bc_vec_push(&p->func->labels, &ip.idx);
4331 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4333 return bc_lex_next(&p->l);
4336 static BcStatus bc_parse_while(BcParse *p)
4341 s = bc_lex_next(&p->l);
4343 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4344 s = bc_lex_next(&p->l);
4347 ip.idx = p->func->labels.len;
4349 bc_vec_push(&p->func->labels, &p->func->code.len);
4350 bc_vec_push(&p->conds, &ip.idx);
4352 ip.idx = p->func->labels.len;
4356 bc_vec_push(&p->exits, &ip);
4357 bc_vec_push(&p->func->labels, &ip.idx);
4359 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4361 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4362 s = bc_lex_next(&p->l);
4365 bc_parse_push(p, BC_INST_JUMP_ZERO);
4366 bc_parse_pushIndex(p, ip.idx);
4367 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4369 return BC_STATUS_SUCCESS;
4372 static BcStatus bc_parse_for(BcParse *p)
4376 size_t cond_idx, exit_idx, body_idx, update_idx;
4378 s = bc_lex_next(&p->l);
4380 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4381 s = bc_lex_next(&p->l);
4384 if (p->l.t.t != BC_LEX_SCOLON)
4385 s = bc_parse_expr(p, 0, bc_parse_next_for);
4387 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4390 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4391 s = bc_lex_next(&p->l);
4394 cond_idx = p->func->labels.len;
4395 update_idx = cond_idx + 1;
4396 body_idx = update_idx + 1;
4397 exit_idx = body_idx + 1;
4399 bc_vec_push(&p->func->labels, &p->func->code.len);
4401 if (p->l.t.t != BC_LEX_SCOLON)
4402 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4404 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4407 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4409 s = bc_lex_next(&p->l);
4412 bc_parse_push(p, BC_INST_JUMP_ZERO);
4413 bc_parse_pushIndex(p, exit_idx);
4414 bc_parse_push(p, BC_INST_JUMP);
4415 bc_parse_pushIndex(p, body_idx);
4417 ip.idx = p->func->labels.len;
4419 bc_vec_push(&p->conds, &update_idx);
4420 bc_vec_push(&p->func->labels, &p->func->code.len);
4422 if (p->l.t.t != BC_LEX_RPAREN)
4423 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4425 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4429 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4430 bc_parse_push(p, BC_INST_JUMP);
4431 bc_parse_pushIndex(p, cond_idx);
4432 bc_vec_push(&p->func->labels, &p->func->code.len);
4438 bc_vec_push(&p->exits, &ip);
4439 bc_vec_push(&p->func->labels, &ip.idx);
4441 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4443 return BC_STATUS_SUCCESS;
4446 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4452 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4454 if (type == BC_LEX_KEY_BREAK) {
4456 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4458 i = p->exits.len - 1;
4459 ip = bc_vec_item(&p->exits, i);
4461 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4462 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4467 i = *((size_t *) bc_vec_top(&p->conds));
4469 bc_parse_push(p, BC_INST_JUMP);
4470 bc_parse_pushIndex(p, i);
4472 s = bc_lex_next(&p->l);
4475 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4476 return BC_STATUS_PARSE_BAD_TOKEN;
4478 return bc_lex_next(&p->l);
4481 static BcStatus bc_parse_func(BcParse *p)
4484 bool var, comma = false;
4488 s = bc_lex_next(&p->l);
4490 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4492 name = xstrdup(p->l.t.v.v);
4493 bc_parse_addFunc(p, name, &p->fidx);
4495 s = bc_lex_next(&p->l);
4497 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4498 s = bc_lex_next(&p->l);
4501 while (p->l.t.t != BC_LEX_RPAREN) {
4503 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4507 name = xstrdup(p->l.t.v.v);
4508 s = bc_lex_next(&p->l);
4511 var = p->l.t.t != BC_LEX_LBRACKET;
4515 s = bc_lex_next(&p->l);
4518 if (p->l.t.t != BC_LEX_RBRACKET) {
4519 s = BC_STATUS_PARSE_BAD_FUNC;
4523 s = bc_lex_next(&p->l);
4527 comma = p->l.t.t == BC_LEX_COMMA;
4529 s = bc_lex_next(&p->l);
4533 s = bc_func_insert(p->func, name, var);
4537 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4539 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4540 bc_parse_startBody(p, flags);
4542 s = bc_lex_next(&p->l);
4545 if (p->l.t.t != BC_LEX_LBRACE)
4546 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4555 static BcStatus bc_parse_auto(BcParse *p)
4558 bool comma, var, one;
4561 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4562 s = bc_lex_next(&p->l);
4565 p->auto_part = comma = false;
4566 one = p->l.t.t == BC_LEX_NAME;
4568 while (p->l.t.t == BC_LEX_NAME) {
4570 name = xstrdup(p->l.t.v.v);
4571 s = bc_lex_next(&p->l);
4574 var = p->l.t.t != BC_LEX_LBRACKET;
4577 s = bc_lex_next(&p->l);
4580 if (p->l.t.t != BC_LEX_RBRACKET) {
4581 s = BC_STATUS_PARSE_BAD_FUNC;
4585 s = bc_lex_next(&p->l);
4589 comma = p->l.t.t == BC_LEX_COMMA;
4591 s = bc_lex_next(&p->l);
4595 s = bc_func_insert(p->func, name, var);
4599 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4600 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4602 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4603 return BC_STATUS_PARSE_BAD_TOKEN;
4605 return bc_lex_next(&p->l);
4612 static BcStatus bc_parse_body(BcParse *p, bool brace)
4614 BcStatus s = BC_STATUS_SUCCESS;
4615 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4617 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4619 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4621 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4622 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4624 if (!p->auto_part) {
4625 s = bc_parse_auto(p);
4629 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4632 s = bc_parse_stmt(p);
4633 if (!s && !brace) s = bc_parse_endBody(p, false);
4639 static BcStatus bc_parse_stmt(BcParse *p)
4641 BcStatus s = BC_STATUS_SUCCESS;
4647 return bc_lex_next(&p->l);
4650 case BC_LEX_KEY_ELSE:
4652 p->auto_part = false;
4658 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4661 s = bc_lex_next(&p->l);
4664 return bc_parse_body(p, true);
4667 case BC_LEX_KEY_AUTO:
4669 return bc_parse_auto(p);
4674 p->auto_part = false;
4676 if (BC_PARSE_IF_END(p)) {
4678 return BC_STATUS_SUCCESS;
4680 else if (BC_PARSE_BODY(p))
4681 return bc_parse_body(p, false);
4691 case BC_LEX_OP_MINUS:
4692 case BC_LEX_OP_BOOL_NOT:
4696 case BC_LEX_KEY_IBASE:
4697 case BC_LEX_KEY_LAST:
4698 case BC_LEX_KEY_LENGTH:
4699 case BC_LEX_KEY_OBASE:
4700 case BC_LEX_KEY_READ:
4701 case BC_LEX_KEY_SCALE:
4702 case BC_LEX_KEY_SQRT:
4704 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4708 case BC_LEX_KEY_ELSE:
4710 s = bc_parse_else(p);
4716 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4722 s = bc_parse_endBody(p, true);
4728 s = bc_parse_string(p, BC_INST_PRINT_STR);
4732 case BC_LEX_KEY_BREAK:
4733 case BC_LEX_KEY_CONTINUE:
4735 s = bc_parse_loopExit(p, p->l.t.t);
4739 case BC_LEX_KEY_FOR:
4741 s = bc_parse_for(p);
4745 case BC_LEX_KEY_HALT:
4747 bc_parse_push(p, BC_INST_HALT);
4748 s = bc_lex_next(&p->l);
4758 case BC_LEX_KEY_LIMITS:
4760 s = bc_lex_next(&p->l);
4762 s = BC_STATUS_LIMITS;
4766 case BC_LEX_KEY_PRINT:
4768 s = bc_parse_print(p);
4772 case BC_LEX_KEY_QUIT:
4774 // Quit is a compile-time command. We don't exit directly,
4775 // so the vm can clean up. Limits do the same thing.
4780 case BC_LEX_KEY_RETURN:
4782 s = bc_parse_return(p);
4786 case BC_LEX_KEY_WHILE:
4788 s = bc_parse_while(p);
4794 s = BC_STATUS_PARSE_BAD_TOKEN;
4802 static BcStatus bc_parse_parse(BcParse *p)
4806 if (p->l.t.t == BC_LEX_EOF)
4807 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4808 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4809 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4810 s = bc_parse_func(p);
4813 s = bc_parse_stmt(p);
4815 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || bcg.signe)
4816 s = bc_parse_reset(p, s);
4821 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4823 BcStatus s = BC_STATUS_SUCCESS;
4824 BcInst prev = BC_INST_PRINT;
4825 BcLexType top, t = p->l.t.t;
4826 size_t nexprs = 0, ops_bgn = p->ops.len;
4827 uint32_t i, nparens, nrelops;
4828 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4830 paren_first = p->l.t.t == BC_LEX_LPAREN;
4831 nparens = nrelops = 0;
4832 paren_expr = rprn = done = get_token = assign = false;
4835 for (; !bcg.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4841 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4842 rprn = get_token = bin_last = false;
4846 case BC_LEX_OP_MINUS:
4848 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4849 rprn = get_token = false;
4850 bin_last = prev == BC_INST_MINUS;
4854 case BC_LEX_OP_ASSIGN_POWER:
4855 case BC_LEX_OP_ASSIGN_MULTIPLY:
4856 case BC_LEX_OP_ASSIGN_DIVIDE:
4857 case BC_LEX_OP_ASSIGN_MODULUS:
4858 case BC_LEX_OP_ASSIGN_PLUS:
4859 case BC_LEX_OP_ASSIGN_MINUS:
4860 case BC_LEX_OP_ASSIGN:
4862 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4863 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4864 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4866 s = BC_STATUS_PARSE_BAD_ASSIGN;
4871 case BC_LEX_OP_POWER:
4872 case BC_LEX_OP_MULTIPLY:
4873 case BC_LEX_OP_DIVIDE:
4874 case BC_LEX_OP_MODULUS:
4875 case BC_LEX_OP_PLUS:
4876 case BC_LEX_OP_REL_EQ:
4877 case BC_LEX_OP_REL_LE:
4878 case BC_LEX_OP_REL_GE:
4879 case BC_LEX_OP_REL_NE:
4880 case BC_LEX_OP_REL_LT:
4881 case BC_LEX_OP_REL_GT:
4882 case BC_LEX_OP_BOOL_NOT:
4883 case BC_LEX_OP_BOOL_OR:
4884 case BC_LEX_OP_BOOL_AND:
4886 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4887 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4889 return BC_STATUS_PARSE_BAD_EXP;
4892 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4893 prev = BC_PARSE_TOKEN_INST(t);
4894 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4895 rprn = get_token = false;
4896 bin_last = t != BC_LEX_OP_BOOL_NOT;
4903 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4906 paren_expr = rprn = bin_last = false;
4908 bc_vec_push(&p->ops, &t);
4915 if (bin_last || prev == BC_INST_BOOL_NOT)
4916 return BC_STATUS_PARSE_BAD_EXP;
4919 s = BC_STATUS_SUCCESS;
4924 else if (!paren_expr)
4925 return BC_STATUS_PARSE_EMPTY_EXP;
4928 paren_expr = rprn = true;
4929 get_token = bin_last = false;
4931 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4938 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4941 rprn = get_token = bin_last = false;
4942 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4950 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4952 bc_parse_number(p, &prev, &nexprs);
4953 paren_expr = get_token = true;
4954 rprn = bin_last = false;
4959 case BC_LEX_KEY_IBASE:
4960 case BC_LEX_KEY_LAST:
4961 case BC_LEX_KEY_OBASE:
4963 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4965 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4966 bc_parse_push(p, (char) prev);
4968 paren_expr = get_token = true;
4969 rprn = bin_last = false;
4975 case BC_LEX_KEY_LENGTH:
4976 case BC_LEX_KEY_SQRT:
4978 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4980 s = bc_parse_builtin(p, t, flags, &prev);
4982 rprn = get_token = bin_last = false;
4988 case BC_LEX_KEY_READ:
4990 if (BC_PARSE_LEAF(prev, rprn))
4991 return BC_STATUS_PARSE_BAD_EXP;
4992 else if (flags & BC_PARSE_NOREAD)
4993 s = BC_STATUS_EXEC_REC_READ;
4995 s = bc_parse_read(p);
4998 rprn = get_token = bin_last = false;
5000 prev = BC_INST_READ;
5005 case BC_LEX_KEY_SCALE:
5007 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
5009 s = bc_parse_scale(p, &prev, flags);
5011 rprn = get_token = bin_last = false;
5013 prev = BC_INST_SCALE;
5020 s = BC_STATUS_PARSE_BAD_TOKEN;
5025 if (!s && get_token) s = bc_lex_next(&p->l);
5029 if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
5031 while (p->ops.len > ops_bgn) {
5033 top = BC_PARSE_TOP_OP(p);
5034 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
5036 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
5037 return BC_STATUS_PARSE_BAD_EXP;
5039 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5041 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5042 bc_vec_pop(&p->ops);
5045 s = BC_STATUS_PARSE_BAD_EXP;
5046 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5048 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5051 if (!(flags & BC_PARSE_REL) && nrelops) {
5052 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5055 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5056 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5060 if (flags & BC_PARSE_PRINT) {
5061 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5062 bc_parse_push(p, BC_INST_POP);
5068 static void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5070 bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
5073 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5075 return bc_parse_expr(p, flags, bc_parse_next_read);
5080 static BcStatus dc_parse_register(BcParse *p)
5085 s = bc_lex_next(&p->l);
5087 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5089 name = xstrdup(p->l.t.v.v);
5090 bc_parse_pushName(p, name);
5095 static BcStatus dc_parse_string(BcParse *p)
5097 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5098 size_t idx, len = p->prog->strs.len;
5100 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5103 str = xstrdup(p->l.t.v.v);
5104 bc_parse_push(p, BC_INST_STR);
5105 bc_parse_pushIndex(p, len);
5106 bc_vec_push(&p->prog->strs, &str);
5107 bc_parse_addFunc(p, name, &idx);
5109 return bc_lex_next(&p->l);
5112 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5116 bc_parse_push(p, inst);
5118 s = dc_parse_register(p);
5123 bc_parse_push(p, BC_INST_SWAP);
5124 bc_parse_push(p, BC_INST_ASSIGN);
5125 bc_parse_push(p, BC_INST_POP);
5128 return bc_lex_next(&p->l);
5131 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5135 bc_parse_push(p, inst);
5136 bc_parse_push(p, BC_INST_EXEC_COND);
5138 s = dc_parse_register(p);
5141 s = bc_lex_next(&p->l);
5144 if (p->l.t.t == BC_LEX_ELSE) {
5145 s = dc_parse_register(p);
5147 s = bc_lex_next(&p->l);
5150 bc_parse_push(p, BC_PARSE_STREND);
5155 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5157 BcStatus s = BC_STATUS_SUCCESS;
5160 bool assign, get_token = false;
5164 case BC_LEX_OP_REL_EQ:
5165 case BC_LEX_OP_REL_LE:
5166 case BC_LEX_OP_REL_GE:
5167 case BC_LEX_OP_REL_NE:
5168 case BC_LEX_OP_REL_LT:
5169 case BC_LEX_OP_REL_GT:
5171 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5178 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5184 s = dc_parse_string(p);
5191 if (t == BC_LEX_NEG) {
5192 s = bc_lex_next(&p->l);
5194 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5197 bc_parse_number(p, &prev, &p->nbraces);
5199 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5205 case BC_LEX_KEY_READ:
5207 if (flags & BC_PARSE_NOREAD)
5208 s = BC_STATUS_EXEC_REC_READ;
5210 bc_parse_push(p, BC_INST_READ);
5215 case BC_LEX_OP_ASSIGN:
5216 case BC_LEX_STORE_PUSH:
5218 assign = t == BC_LEX_OP_ASSIGN;
5219 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5220 s = dc_parse_mem(p, inst, true, assign);
5225 case BC_LEX_LOAD_POP:
5227 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5228 s = dc_parse_mem(p, inst, true, false);
5232 case BC_LEX_STORE_IBASE:
5233 case BC_LEX_STORE_SCALE:
5234 case BC_LEX_STORE_OBASE:
5236 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5237 s = dc_parse_mem(p, inst, false, true);
5243 s = BC_STATUS_PARSE_BAD_TOKEN;
5249 if (!s && get_token) s = bc_lex_next(&p->l);
5254 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5256 BcStatus s = BC_STATUS_SUCCESS;
5260 if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
5262 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5264 inst = dc_parse_insts[t];
5266 if (inst != BC_INST_INVALID) {
5267 bc_parse_push(p, inst);
5268 s = bc_lex_next(&p->l);
5271 s = dc_parse_token(p, t, flags);
5274 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5275 bc_parse_push(p, BC_INST_POP_EXEC);
5280 static BcStatus dc_parse_parse(BcParse *p)
5284 if (p->l.t.t == BC_LEX_EOF)
5285 s = BC_STATUS_LEX_EOF;
5287 s = dc_parse_expr(p, 0);
5289 if (s || bcg.signe) s = bc_parse_reset(p, s);
5294 static void dc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5296 bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
5300 static void bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
5309 v = var ? &p->vars : &p->arrs;
5310 map = var ? &p->var_map : &p->arr_map;
5314 s = bc_map_insert(map, &e, &i);
5315 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5318 bc_array_init(&data.v, var);
5319 bc_vec_push(v, &data.v);
5322 ptr = bc_vec_item(map, i);
5323 if (new) ptr->name = xstrdup(e.name);
5324 *ret = bc_vec_item(v, ptr->idx);
5327 static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
5329 BcStatus s = BC_STATUS_SUCCESS;
5334 case BC_RESULT_TEMP:
5335 case BC_RESULT_IBASE:
5336 case BC_RESULT_SCALE:
5337 case BC_RESULT_OBASE:
5343 case BC_RESULT_CONSTANT:
5345 char **str = bc_vec_item(&p->consts, r->d.id.idx);
5346 size_t base_t, len = strlen(*str);
5349 bc_num_init(&r->d.n, len);
5351 hex = hex && len == 1;
5352 base = hex ? &p->hexb : &p->ib;
5353 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
5354 s = bc_num_parse(&r->d.n, *str, base, base_t);
5357 bc_num_free(&r->d.n);
5362 r->t = BC_RESULT_TEMP;
5368 case BC_RESULT_ARRAY:
5369 case BC_RESULT_ARRAY_ELEM:
5373 bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
5375 if (r->t == BC_RESULT_ARRAY_ELEM) {
5377 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5378 *num = bc_vec_item(v, r->d.id.idx);
5381 *num = bc_vec_top(v);
5386 case BC_RESULT_LAST:
5402 static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
5403 BcResult **r, BcNum **rn, bool assign)
5407 BcResultType lt, rt;
5409 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5411 *r = bc_vec_item_rev(&p->results, 0);
5412 *l = bc_vec_item_rev(&p->results, 1);
5416 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5418 s = bc_program_num(p, *l, ln, false);
5420 s = bc_program_num(p, *r, rn, hex);
5423 // We run this again under these conditions in case any vector has been
5424 // reallocated out from under the BcNums or arrays we had.
5425 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5426 s = bc_program_num(p, *l, ln, false);
5430 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5431 return BC_STATUS_EXEC_BAD_TYPE;
5432 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5437 static void bc_program_binOpRetire(BcProgram *p, BcResult *r)
5439 r->t = BC_RESULT_TEMP;
5440 bc_vec_pop(&p->results);
5441 bc_vec_pop(&p->results);
5442 bc_vec_push(&p->results, r);
5445 static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n)
5449 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5450 *r = bc_vec_top(&p->results);
5452 s = bc_program_num(p, *r, n, false);
5455 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5460 static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t)
5463 bc_vec_pop(&p->results);
5464 bc_vec_push(&p->results, r);
5467 static BcStatus bc_program_op(BcProgram *p, char inst)
5470 BcResult *opd1, *opd2, res;
5471 BcNum *n1, *n2 = NULL;
5473 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5475 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5477 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale);
5479 bc_program_binOpRetire(p, &res);
5484 bc_num_free(&res.d.n);
5488 static BcStatus bc_program_read(BcProgram *p)
5495 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
5497 for (i = 0; i < p->stack.len; ++i) {
5498 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
5499 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5502 bc_vec_npop(&f->code, f->code.len);
5503 bc_vec_init(&buf, sizeof(char), NULL);
5505 s = bc_read_line(&buf, "read> ");
5508 p->parse_init(&parse, p, BC_PROG_READ);
5509 bc_lex_file(&parse.l, bc_program_stdin_name);
5511 s = bc_parse_text(&parse, buf.v);
5512 if (s) goto exec_err;
5513 s = p->parse_expr(&parse, BC_PARSE_NOREAD);
5514 if (s) goto exec_err;
5516 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5517 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5521 ip.func = BC_PROG_READ;
5523 ip.len = p->results.len;
5525 // Update this pointer, just in case.
5526 f = bc_vec_item(&p->fns, BC_PROG_READ);
5528 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5529 bc_vec_push(&p->stack, &ip);
5532 bc_parse_free(&parse);
5538 static size_t bc_program_index(char *code, size_t *bgn)
5540 char amt = code[(*bgn)++], i = 0;
5543 for (; i < amt; ++i, ++(*bgn))
5544 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5549 static char *bc_program_name(char *code, size_t *bgn)
5552 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5554 s = xmalloc(ptr - str + 1);
5557 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5565 static void bc_program_printString(const char *str, size_t *nchars)
5567 size_t i, len = strlen(str);
5576 for (i = 0; i < len; ++i, ++(*nchars)) {
5580 if (c != '\\' || i == len - 1)
5640 // Just print the backslash and following character.
5651 static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
5653 BcStatus s = BC_STATUS_SUCCESS;
5658 bool pop = inst != BC_INST_PRINT;
5660 if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
5662 r = bc_vec_item_rev(&p->results, idx);
5663 s = bc_program_num(p, r, &num, false);
5666 if (BC_PROG_NUM(r, num)) {
5667 s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
5668 if (!s) bc_num_copy(&p->last, num);
5672 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5673 str = *((char **) bc_vec_item(&p->strs, idx));
5675 if (inst == BC_INST_PRINT_STR) {
5676 for (i = 0, len = strlen(str); i < len; ++i) {
5679 if (c == '\n') p->nchars = SIZE_MAX;
5684 bc_program_printString(str, &p->nchars);
5685 if (inst == BC_INST_PRINT) bb_putchar('\n');
5689 if (!s && pop) bc_vec_pop(&p->results);
5694 static BcStatus bc_program_negate(BcProgram *p)
5700 s = bc_program_prep(p, &ptr, &num);
5703 bc_num_init(&res.d.n, num->len);
5704 bc_num_copy(&res.d.n, num);
5705 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5707 bc_program_retire(p, &res, BC_RESULT_TEMP);
5712 static BcStatus bc_program_logical(BcProgram *p, char inst)
5715 BcResult *opd1, *opd2, res;
5720 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5722 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5724 if (inst == BC_INST_BOOL_AND)
5725 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
5726 else if (inst == BC_INST_BOOL_OR)
5727 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
5730 cmp = bc_num_cmp(n1, n2);
5734 case BC_INST_REL_EQ:
5740 case BC_INST_REL_LE:
5746 case BC_INST_REL_GE:
5752 case BC_INST_REL_NE:
5758 case BC_INST_REL_LT:
5764 case BC_INST_REL_GT:
5772 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5774 bc_program_binOpRetire(p, &res);
5780 static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
5786 memset(&n2, 0, sizeof(BcNum));
5787 n2.rdx = res.d.id.idx = r->d.id.idx;
5788 res.t = BC_RESULT_STR;
5791 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5793 bc_vec_pop(&p->results);
5796 bc_vec_pop(&p->results);
5798 bc_vec_push(&p->results, &res);
5799 bc_vec_push(v, &n2);
5801 return BC_STATUS_SUCCESS;
5805 static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var)
5812 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5814 ptr = bc_vec_top(&p->results);
5815 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5816 bc_program_search(p, name, &v, var);
5819 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5820 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
5823 s = bc_program_num(p, ptr, &n, false);
5826 // Do this once more to make sure that pointers were not invalidated.
5827 bc_program_search(p, name, &v, var);
5830 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5831 bc_num_copy(&r.d.n, n);
5834 bc_array_init(&r.d.v, true);
5835 bc_array_copy(&r.d.v, (BcVec *) n);
5838 bc_vec_push(v, &r.d);
5839 bc_vec_pop(&p->results);
5844 static BcStatus bc_program_assign(BcProgram *p, char inst)
5847 BcResult *left, *right, res;
5848 BcNum *l = NULL, *r = NULL;
5849 unsigned long val, max;
5850 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5852 s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign);
5855 ib = left->t == BC_RESULT_IBASE;
5856 sc = left->t == BC_RESULT_SCALE;
5860 if (right->t == BC_RESULT_STR) {
5864 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5865 bc_program_search(p, left->d.id.name, &v, true);
5867 return bc_program_assignStr(p, right, v, false);
5871 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5872 return BC_STATUS_PARSE_BAD_ASSIGN;
5875 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
5876 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5881 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5888 if (ib || sc || left->t == BC_RESULT_OBASE) {
5892 s = bc_num_ulong(l, &val);
5894 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5901 if (val < BC_NUM_MIN_BASE) return s;
5902 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5903 ptr = ib ? &p->ib_t : &p->ob_t;
5906 if (val > max) return s;
5907 if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l);
5909 *ptr = (size_t) val;
5910 s = BC_STATUS_SUCCESS;
5913 bc_num_init(&res.d.n, l->len);
5914 bc_num_copy(&res.d.n, l);
5915 bc_program_binOpRetire(p, &res);
5920 static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
5921 bool pop, bool copy)
5923 BcStatus s = BC_STATUS_SUCCESS;
5925 char *name = bc_program_name(code, bgn);
5926 #if ENABLE_DC // Exclude
5930 (void) pop, (void) copy;
5933 r.t = BC_RESULT_VAR;
5937 bc_program_search(p, name, &v, true);
5938 num = bc_vec_top(v);
5942 if (!BC_PROG_STACK(v, 2 - copy)) {
5944 return BC_STATUS_EXEC_STACK;
5950 if (!BC_PROG_STR(num)) {
5952 r.t = BC_RESULT_TEMP;
5954 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5955 bc_num_copy(&r.d.n, num);
5958 r.t = BC_RESULT_STR;
5959 r.d.id.idx = num->rdx;
5962 if (!copy) bc_vec_pop(v);
5966 bc_vec_push(&p->results, &r);
5971 static BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn,
5974 BcStatus s = BC_STATUS_SUCCESS;
5978 r.d.id.name = bc_program_name(code, bgn);
5980 if (inst == BC_INST_ARRAY) {
5981 r.t = BC_RESULT_ARRAY;
5982 bc_vec_push(&p->results, &r);
5989 s = bc_program_prep(p, &operand, &num);
5991 s = bc_num_ulong(num, &temp);
5994 if (temp > BC_MAX_DIM) {
5995 s = BC_STATUS_EXEC_ARRAY_LEN;
5999 r.d.id.idx = (size_t) temp;
6000 bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
6004 if (s) free(r.d.id.name);
6009 static BcStatus bc_program_incdec(BcProgram *p, char inst)
6012 BcResult *ptr, res, copy;
6016 s = bc_program_prep(p, &ptr, &num);
6019 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6020 copy.t = BC_RESULT_TEMP;
6021 bc_num_init(©.d.n, num->len);
6022 bc_num_copy(©.d.n, num);
6025 res.t = BC_RESULT_ONE;
6026 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6027 BC_INST_ASSIGN_PLUS :
6028 BC_INST_ASSIGN_MINUS;
6030 bc_vec_push(&p->results, &res);
6031 bc_program_assign(p, inst);
6033 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
6034 bc_vec_pop(&p->results);
6035 bc_vec_push(&p->results, ©);
6041 static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx)
6043 BcStatus s = BC_STATUS_SUCCESS;
6045 size_t i, nparams = bc_program_index(code, idx);
6053 ip.func = bc_program_index(code, idx);
6054 func = bc_vec_item(&p->fns, ip.func);
6056 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6057 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6058 ip.len = p->results.len - nparams;
6060 for (i = 0; i < nparams; ++i) {
6062 a = bc_vec_item(&func->autos, nparams - 1 - i);
6063 arg = bc_vec_top(&p->results);
6065 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6066 return BC_STATUS_EXEC_BAD_TYPE;
6068 s = bc_program_copyToVar(p, a->name, a->idx);
6072 for (; i < func->autos.len; ++i) {
6074 a = bc_vec_item(&func->autos, i);
6075 bc_program_search(p, a->name, &v, a->idx);
6078 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6079 bc_vec_push(v, ¶m.n);
6082 bc_array_init(¶m.v, true);
6083 bc_vec_push(v, ¶m.v);
6087 bc_vec_push(&p->stack, &ip);
6089 return BC_STATUS_SUCCESS;
6092 static BcStatus bc_program_return(BcProgram *p, char inst)
6098 BcInstPtr *ip = bc_vec_top(&p->stack);
6100 if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
6101 return BC_STATUS_EXEC_STACK;
6103 f = bc_vec_item(&p->fns, ip->func);
6104 res.t = BC_RESULT_TEMP;
6106 if (inst == BC_INST_RET) {
6109 BcResult *operand = bc_vec_top(&p->results);
6111 s = bc_program_num(p, operand, &num, false);
6113 bc_num_init(&res.d.n, num->len);
6114 bc_num_copy(&res.d.n, num);
6117 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6118 bc_num_zero(&res.d.n);
6121 // We need to pop arguments as well, so this takes that into account.
6122 for (i = 0; i < f->autos.len; ++i) {
6125 BcId *a = bc_vec_item(&f->autos, i);
6127 bc_program_search(p, a->name, &v, a->idx);
6131 bc_vec_npop(&p->results, p->results.len - ip->len);
6132 bc_vec_push(&p->results, &res);
6133 bc_vec_pop(&p->stack);
6135 return BC_STATUS_SUCCESS;
6139 static unsigned long bc_program_scale(BcNum *n)
6141 return (unsigned long) n->rdx;
6144 static unsigned long bc_program_len(BcNum *n)
6146 unsigned long len = n->len;
6149 if (n->rdx != n->len) return len;
6150 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6155 static BcStatus bc_program_builtin(BcProgram *p, char inst)
6161 bool len = inst == BC_INST_LENGTH;
6163 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6164 opnd = bc_vec_top(&p->results);
6166 s = bc_program_num(p, opnd, &num, false);
6170 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6173 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6175 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
6177 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6178 s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6182 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6185 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6187 str = bc_vec_item(&p->strs, idx);
6188 s = bc_num_ulong2num(&res.d.n, strlen(*str));
6193 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6194 s = bc_num_ulong2num(&res.d.n, f(num));
6198 bc_program_retire(p, &res, BC_RESULT_TEMP);
6203 bc_num_free(&res.d.n);
6208 static BcStatus bc_program_divmod(BcProgram *p)
6211 BcResult *opd1, *opd2, res, res2;
6212 BcNum *n1, *n2 = NULL;
6214 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
6217 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6218 bc_num_init(&res2.d.n, n2->len);
6220 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale);
6223 bc_program_binOpRetire(p, &res2);
6224 res.t = BC_RESULT_TEMP;
6225 bc_vec_push(&p->results, &res);
6230 bc_num_free(&res2.d.n);
6231 bc_num_free(&res.d.n);
6235 static BcStatus bc_program_modexp(BcProgram *p)
6238 BcResult *r1, *r2, *r3, res;
6239 BcNum *n1, *n2, *n3;
6241 if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
6242 s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false);
6245 r1 = bc_vec_item_rev(&p->results, 2);
6246 s = bc_program_num(p, r1, &n1, false);
6248 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6250 // Make sure that the values have their pointers updated, if necessary.
6251 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6253 if (r1->t == r2->t) {
6254 s = bc_program_num(p, r2, &n2, false);
6258 if (r1->t == r3->t) {
6259 s = bc_program_num(p, r3, &n3, false);
6264 bc_num_init(&res.d.n, n3->len);
6265 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6268 bc_vec_pop(&p->results);
6269 bc_program_binOpRetire(p, &res);
6274 bc_num_free(&res.d.n);
6278 static BcStatus bc_program_stackLen(BcProgram *p)
6282 size_t len = p->results.len;
6284 res.t = BC_RESULT_TEMP;
6286 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6287 s = bc_num_ulong2num(&res.d.n, len);
6289 bc_vec_push(&p->results, &res);
6294 bc_num_free(&res.d.n);
6298 static BcStatus bc_program_asciify(BcProgram *p)
6302 BcNum *num = NULL, n;
6303 char *str, *str2, c;
6304 size_t len = p->strs.len, idx;
6307 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6308 r = bc_vec_top(&p->results);
6310 s = bc_program_num(p, r, &num, false);
6313 if (BC_PROG_NUM(r, num)) {
6315 bc_num_init(&n, BC_NUM_DEF_SIZE);
6316 bc_num_copy(&n, num);
6317 bc_num_truncate(&n, n.rdx);
6319 s = bc_num_mod(&n, &p->strmb, &n, 0);
6320 if (s) goto num_err;
6321 s = bc_num_ulong(&n, &val);
6322 if (s) goto num_err;
6329 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6330 str2 = *((char **) bc_vec_item(&p->strs, idx));
6338 str2 = xstrdup(str);
6339 bc_program_addFunc(p, str2, &idx);
6341 if (idx != len + BC_PROG_REQ_FUNCS) {
6343 for (idx = 0; idx < p->strs.len; ++idx) {
6344 if (!strcmp(*((char **) bc_vec_item(&p->strs, idx)), str)) {
6353 bc_vec_push(&p->strs, &str);
6355 res.t = BC_RESULT_STR;
6357 bc_vec_pop(&p->results);
6358 bc_vec_push(&p->results, &res);
6360 return BC_STATUS_SUCCESS;
6367 static BcStatus bc_program_printStream(BcProgram *p)
6375 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6376 r = bc_vec_top(&p->results);
6378 s = bc_program_num(p, r, &n, false);
6381 if (BC_PROG_NUM(r, n))
6382 s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
6384 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6385 str = *((char **) bc_vec_item(&p->strs, idx));
6392 static BcStatus bc_program_nquit(BcProgram *p)
6399 s = bc_program_prep(p, &opnd, &num);
6401 s = bc_num_ulong(num, &val);
6404 bc_vec_pop(&p->results);
6406 if (p->stack.len < val)
6407 return BC_STATUS_EXEC_STACK;
6408 else if (p->stack.len == val)
6409 return BC_STATUS_QUIT;
6411 bc_vec_npop(&p->stack, val);
6416 static BcStatus bc_program_execStr(BcProgram *p, char *code, size_t *bgn,
6419 BcStatus s = BC_STATUS_SUCCESS;
6429 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6431 r = bc_vec_top(&p->results);
6436 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6438 if (code[*bgn] == BC_PARSE_STREND)
6441 else_name = bc_program_name(code, bgn);
6443 exec = r->d.n.len != 0;
6447 else if (else_name != NULL) {
6453 bc_program_search(p, name, &v, true);
6460 if (!exec) goto exit;
6461 if (!BC_PROG_STR(n)) {
6462 s = BC_STATUS_EXEC_BAD_TYPE;
6470 if (r->t == BC_RESULT_STR)
6472 else if (r->t == BC_RESULT_VAR) {
6473 s = bc_program_num(p, r, &n, false);
6474 if (s || !BC_PROG_STR(n)) goto exit;
6481 fidx = sidx + BC_PROG_REQ_FUNCS;
6483 str = bc_vec_item(&p->strs, sidx);
6484 f = bc_vec_item(&p->fns, fidx);
6486 if (f->code.len == 0) {
6488 p->parse_init(&prs, p, fidx);
6489 s = bc_parse_text(&prs, *str);
6491 s = p->parse_expr(&prs, BC_PARSE_NOCALL);
6494 if (prs.l.t.t != BC_LEX_EOF) {
6495 s = BC_STATUS_PARSE_BAD_EXP;
6499 bc_parse_free(&prs);
6503 ip.len = p->results.len;
6506 bc_vec_pop(&p->results);
6507 bc_vec_push(&p->stack, &ip);
6509 return BC_STATUS_SUCCESS;
6512 bc_parse_free(&prs);
6513 f = bc_vec_item(&p->fns, fidx);
6514 bc_vec_npop(&f->code, f->code.len);
6516 bc_vec_pop(&p->results);
6521 static BcStatus bc_program_pushGlobal(BcProgram *p, char inst)
6527 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6528 if (inst == BC_INST_IBASE)
6529 val = (unsigned long) p->ib_t;
6530 else if (inst == BC_INST_SCALE)
6531 val = (unsigned long) p->scale;
6533 val = (unsigned long) p->ob_t;
6535 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6536 s = bc_num_ulong2num(&res.d.n, val);
6538 bc_vec_push(&p->results, &res);
6543 bc_num_free(&res.d.n);
6547 static void bc_program_free(BcProgram *p)
6549 bc_num_free(&p->ib);
6550 bc_num_free(&p->ob);
6551 bc_num_free(&p->hexb);
6553 bc_num_free(&p->strmb);
6555 bc_vec_free(&p->fns);
6556 bc_vec_free(&p->fn_map);
6557 bc_vec_free(&p->vars);
6558 bc_vec_free(&p->var_map);
6559 bc_vec_free(&p->arrs);
6560 bc_vec_free(&p->arr_map);
6561 bc_vec_free(&p->strs);
6562 bc_vec_free(&p->consts);
6563 bc_vec_free(&p->results);
6564 bc_vec_free(&p->stack);
6565 bc_num_free(&p->last);
6566 bc_num_free(&p->zero);
6567 bc_num_free(&p->one);
6570 static void bc_program_init(BcProgram *p, size_t line_len, BcParseInit init,
6576 memset(p, 0, sizeof(BcProgram));
6577 memset(&ip, 0, sizeof(BcInstPtr));
6579 p->nchars = p->scale = 0;
6581 p->parse_init = init;
6582 p->parse_expr = expr;
6584 bc_num_init(&p->ib, BC_NUM_DEF_SIZE);
6588 bc_num_init(&p->ob, BC_NUM_DEF_SIZE);
6592 bc_num_init(&p->hexb, BC_NUM_DEF_SIZE);
6593 bc_num_ten(&p->hexb);
6597 bc_num_init(&p->strmb, BC_NUM_DEF_SIZE);
6598 bc_num_ulong2num(&p->strmb, UCHAR_MAX + 1);
6601 bc_num_init(&p->last, BC_NUM_DEF_SIZE);
6602 bc_num_zero(&p->last);
6604 bc_num_init(&p->zero, BC_NUM_DEF_SIZE);
6605 bc_num_zero(&p->zero);
6607 bc_num_init(&p->one, BC_NUM_DEF_SIZE);
6608 bc_num_one(&p->one);
6610 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
6611 bc_map_init(&p->fn_map);
6613 bc_program_addFunc(p, xstrdup(bc_func_main), &idx);
6614 bc_program_addFunc(p, xstrdup(bc_func_read), &idx);
6616 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
6617 bc_map_init(&p->var_map);
6619 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
6620 bc_map_init(&p->arr_map);
6622 bc_vec_init(&p->strs, sizeof(char *), bc_string_free);
6623 bc_vec_init(&p->consts, sizeof(char *), bc_string_free);
6624 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
6625 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
6626 bc_vec_push(&p->stack, &ip);
6629 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx)
6632 BcId entry, *entry_ptr;
6636 entry.idx = p->fns.len;
6638 s = bc_map_insert(&p->fn_map, &entry, idx);
6641 entry_ptr = bc_vec_item(&p->fn_map, *idx);
6642 *idx = entry_ptr->idx;
6644 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6646 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
6648 // We need to reset these, so the function can be repopulated.
6650 bc_vec_npop(&func->autos, func->autos.len);
6651 bc_vec_npop(&func->code, func->code.len);
6652 bc_vec_npop(&func->labels, func->labels.len);
6656 bc_vec_push(&p->fns, &f);
6660 static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
6665 bc_vec_npop(&p->stack, p->stack.len - 1);
6666 bc_vec_npop(&p->results, p->results.len);
6668 f = bc_vec_item(&p->fns, 0);
6669 ip = bc_vec_top(&p->stack);
6670 ip->idx = f->code.len;
6672 if (!s && bcg.signe && !bcg.tty) return BC_STATUS_QUIT;
6674 bcg.sigc += bcg.signe;
6675 bcg.signe = bcg.sig != bcg.sigc;
6677 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6679 fputs(bc_program_ready_msg, stderr);
6681 s = BC_STATUS_SUCCESS;
6690 static BcStatus bc_program_exec(BcProgram *p)
6692 BcStatus s = BC_STATUS_SUCCESS;
6696 BcInstPtr *ip = bc_vec_top(&p->stack);
6697 BcFunc *func = bc_vec_item(&p->fns, ip->func);
6698 char *code = func->code.v;
6701 while (!s && ip->idx < func->code.len) {
6703 char inst = code[(ip->idx)++];
6708 case BC_INST_JUMP_ZERO:
6710 s = bc_program_prep(p, &ptr, &num);
6712 cond = !bc_num_cmp(num, &p->zero);
6713 bc_vec_pop(&p->results);
6719 idx = bc_program_index(code, &ip->idx);
6720 addr = bc_vec_item(&func->labels, idx);
6721 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6727 s = bc_program_call(p, code, &ip->idx);
6731 case BC_INST_INC_PRE:
6732 case BC_INST_DEC_PRE:
6733 case BC_INST_INC_POST:
6734 case BC_INST_DEC_POST:
6736 s = bc_program_incdec(p, inst);
6749 s = bc_program_return(p, inst);
6753 case BC_INST_BOOL_OR:
6754 case BC_INST_BOOL_AND:
6756 case BC_INST_REL_EQ:
6757 case BC_INST_REL_LE:
6758 case BC_INST_REL_GE:
6759 case BC_INST_REL_NE:
6760 case BC_INST_REL_LT:
6761 case BC_INST_REL_GT:
6763 s = bc_program_logical(p, inst);
6769 s = bc_program_read(p);
6775 s = bc_program_pushVar(p, code, &ip->idx, false, false);
6779 case BC_INST_ARRAY_ELEM:
6782 s = bc_program_pushArray(p, code, &ip->idx, inst);
6788 r.t = BC_RESULT_LAST;
6789 bc_vec_push(&p->results, &r);
6797 s = bc_program_pushGlobal(p, inst);
6801 case BC_INST_SCALE_FUNC:
6802 case BC_INST_LENGTH:
6805 s = bc_program_builtin(p, inst);
6811 r.t = BC_RESULT_CONSTANT;
6812 r.d.id.idx = bc_program_index(code, &ip->idx);
6813 bc_vec_push(&p->results, &r);
6819 if (!BC_PROG_STACK(&p->results, 1))
6820 s = BC_STATUS_EXEC_STACK;
6822 bc_vec_pop(&p->results);
6826 case BC_INST_POP_EXEC:
6828 bc_vec_pop(&p->stack);
6833 case BC_INST_PRINT_POP:
6834 case BC_INST_PRINT_STR:
6836 s = bc_program_print(p, inst, 0);
6842 r.t = BC_RESULT_STR;
6843 r.d.id.idx = bc_program_index(code, &ip->idx);
6844 bc_vec_push(&p->results, &r);
6849 case BC_INST_MULTIPLY:
6850 case BC_INST_DIVIDE:
6851 case BC_INST_MODULUS:
6855 s = bc_program_op(p, inst);
6859 case BC_INST_BOOL_NOT:
6861 s = bc_program_prep(p, &ptr, &num);
6864 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6865 (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6866 bc_program_retire(p, &r, BC_RESULT_TEMP);
6873 s = bc_program_negate(p);
6878 case BC_INST_ASSIGN_POWER:
6879 case BC_INST_ASSIGN_MULTIPLY:
6880 case BC_INST_ASSIGN_DIVIDE:
6881 case BC_INST_ASSIGN_MODULUS:
6882 case BC_INST_ASSIGN_PLUS:
6883 case BC_INST_ASSIGN_MINUS:
6885 case BC_INST_ASSIGN:
6887 s = bc_program_assign(p, inst);
6891 case BC_INST_MODEXP:
6893 s = bc_program_modexp(p);
6897 case BC_INST_DIVMOD:
6899 s = bc_program_divmod(p);
6903 case BC_INST_EXECUTE:
6904 case BC_INST_EXEC_COND:
6906 cond = inst == BC_INST_EXEC_COND;
6907 s = bc_program_execStr(p, code, &ip->idx, cond);
6911 case BC_INST_PRINT_STACK:
6913 for (idx = 0; !s && idx < p->results.len; ++idx)
6914 s = bc_program_print(p, BC_INST_PRINT, idx);
6918 case BC_INST_CLEAR_STACK:
6920 bc_vec_npop(&p->results, p->results.len);
6924 case BC_INST_STACK_LEN:
6926 s = bc_program_stackLen(p);
6930 case BC_INST_DUPLICATE:
6932 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6933 ptr = bc_vec_top(&p->results);
6934 bc_result_copy(&r, ptr);
6935 bc_vec_push(&p->results, &r);
6943 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
6945 ptr = bc_vec_item_rev(&p->results, 0);
6946 ptr2 = bc_vec_item_rev(&p->results, 1);
6947 memcpy(&r, ptr, sizeof(BcResult));
6948 memcpy(ptr, ptr2, sizeof(BcResult));
6949 memcpy(ptr2, &r, sizeof(BcResult));
6954 case BC_INST_ASCIIFY:
6956 s = bc_program_asciify(p);
6960 case BC_INST_PRINT_STREAM:
6962 s = bc_program_printStream(p);
6967 case BC_INST_PUSH_VAR:
6969 bool copy = inst == BC_INST_LOAD;
6970 s = bc_program_pushVar(p, code, &ip->idx, true, copy);
6974 case BC_INST_PUSH_TO_VAR:
6976 char *name = bc_program_name(code, &ip->idx);
6977 s = bc_program_copyToVar(p, name, true);
6984 if (p->stack.len <= 2)
6987 bc_vec_npop(&p->stack, 2);
6993 s = bc_program_nquit(p);
6999 if ((s && s != BC_STATUS_QUIT) || bcg.signe) s = bc_program_reset(p, s);
7001 // If the stack has changed, pointers may be invalid.
7002 ip = bc_vec_top(&p->stack);
7003 func = bc_vec_item(&p->fns, ip->func);
7004 code = func->code.v;
7010 #if ENABLE_FEATURE_BC_SIGNALS
7011 static void bc_vm_sig(int sig)
7014 size_t len = strlen(bcg.sig_msg);
7015 if (sig == SIGINT && write(2, bcg.sig_msg, len) == (ssize_t) len) {
7016 bcg.signe = bcg.sig == bcg.sigc;
7017 bcg.sig += bcg.signe;
7023 static void bc_vm_info(void)
7025 printf("%s "BB_VER"\n"
7026 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
7027 "Report bugs at: https://github.com/gavinhoward/bc\n\n"
7028 "This is free software with ABSOLUTELY NO WARRANTY\n"
7032 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
7034 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
7036 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7037 fprintf(stderr, " %s", file);
7038 fprintf(stderr, bc_err_line + 4 * !line, line);
7040 return s * (!bcg.ttyin || !!strcmp(file, bc_program_stdin_name));
7044 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
7047 int p = (int) bcg.posix, w = (int) bcg.warn;
7048 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
7050 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
7052 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7053 if (msg) fprintf(stderr, " %s\n", msg);
7054 fprintf(stderr, " %s", file);
7055 fprintf(stderr, bc_err_line + 4 * !line, line);
7057 return s * (!bcg.ttyin && !!p);
7060 static BcStatus bc_vm_envArgs(BcVm *vm)
7062 BcStatus s = BC_STATUS_SUCCESS;
7064 char *env_args = getenv(bc_args_env_name), *buf;
7066 if (!env_args) return s;
7068 vm->env_args = xstrdup(env_args);
7071 bc_vec_init(&v, sizeof(char *), NULL);
7072 bc_vec_push(&v, &bc_args_env_name);
7075 if (!isspace(*buf)) {
7076 bc_vec_push(&v, &buf);
7077 while (*buf != 0 && !isspace(*buf)) ++buf;
7078 if (*buf != 0) (*(buf++)) = '\0';
7084 s = bc_args((int) v.len, (char **) v.v, &vm->flags, &vm->files);
7092 static size_t bc_vm_envLen(const char *var)
7094 char *lenv = getenv(var);
7095 size_t i, len = BC_NUM_PRINT_WIDTH;
7098 if (!lenv) return len;
7102 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
7104 len = (size_t) atoi(lenv) - 1;
7105 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
7108 len = BC_NUM_PRINT_WIDTH;
7113 static BcStatus bc_vm_process(BcVm *vm, const char *text)
7115 BcStatus s = bc_parse_text(&vm->prs, text);
7117 s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line);
7120 while (vm->prs.l.t.t != BC_LEX_EOF) {
7122 s = vm->prs.parse(&vm->prs);
7124 if (s == BC_STATUS_LIMITS) {
7127 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
7128 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
7129 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
7130 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
7131 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
7132 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
7133 printf("Max Exponent = %lu\n", BC_MAX_EXP);
7134 printf("Number of Vars = %lu\n", BC_MAX_VARS);
7137 s = BC_STATUS_SUCCESS;
7140 if (s == BC_STATUS_QUIT) return s;
7141 s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line);
7146 if (BC_PARSE_CAN_EXEC(&vm->prs)) {
7147 s = bc_program_exec(&vm->prog);
7148 if (!s && bcg.tty) fflush(stdout);
7149 if (s && s != BC_STATUS_QUIT)
7150 s = bc_vm_error(bc_program_reset(&vm->prog, s), vm->prs.l.f, 0);
7156 static BcStatus bc_vm_file(BcVm *vm, const char *file)
7163 vm->prog.file = file;
7164 s = bc_read_file(file, &data);
7165 if (s) return bc_vm_error(s, file, 0);
7167 bc_lex_file(&vm->prs.l, file);
7168 s = bc_vm_process(vm, data);
7171 main_func = bc_vec_item(&vm->prog.fns, BC_PROG_MAIN);
7172 ip = bc_vec_item(&vm->prog.stack, 0);
7174 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7181 static BcStatus bc_vm_stdin(BcVm *vm)
7183 BcStatus s = BC_STATUS_SUCCESS;
7186 size_t len, i, str = 0;
7187 bool comment = false, notend;
7189 vm->prog.file = bc_program_stdin_name;
7190 bc_lex_file(&vm->prs.l, bc_program_stdin_name);
7192 bc_vec_init(&buffer, sizeof(char), NULL);
7193 bc_vec_init(&buf, sizeof(char), NULL);
7194 bc_vec_pushByte(&buffer, '\0');
7196 // This loop is complex because the vm tries not to send any lines that end
7197 // with a backslash to the parser. The reason for that is because the parser
7198 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7199 // case, and for strings and comments, the parser will expect more stuff.
7200 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7202 char *string = buf.v;
7207 if (str && buf.v[0] == vm->exe.send)
7209 else if (buf.v[0] == vm->exe.sbgn)
7212 else if (len > 1 || comment) {
7214 for (i = 0; i < len; ++i) {
7216 notend = len > i + 1;
7219 if (i - 1 > len || string[i - 1] != '\\') {
7220 if (vm->exe.sbgn == vm->exe.send)
7221 str ^= c == vm->exe.sbgn;
7222 else if (c == vm->exe.send)
7224 else if (c == vm->exe.sbgn)
7228 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7232 else if (c == '*' && notend && comment && string[i + 1] == '/')
7236 if (str || comment || string[len - 2] == '\\') {
7237 bc_vec_concat(&buffer, buf.v);
7242 bc_vec_concat(&buffer, buf.v);
7243 s = bc_vm_process(vm, buffer.v);
7246 bc_vec_npop(&buffer, buffer.len);
7249 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, vm->prs.l.f, 0);
7251 // I/O error will always happen when stdin is
7252 // closed. It's not a problem in that case.
7253 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7254 s = BC_STATUS_SUCCESS;
7257 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, vm->prs.l.f,
7260 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, vm->prs.l.f,
7265 bc_vec_free(&buffer);
7269 static BcStatus bc_vm_exec(BcVm *vm)
7271 BcStatus s = BC_STATUS_SUCCESS;
7275 if (vm->flags & BC_FLAG_L) {
7277 bc_lex_file(&vm->prs.l, bc_lib_name);
7278 s = bc_parse_text(&vm->prs, bc_lib);
7280 while (!s && vm->prs.l.t.t != BC_LEX_EOF) s = vm->prs.parse(&vm->prs);
7283 s = bc_program_exec(&vm->prog);
7288 for (i = 0; !s && i < vm->files.len; ++i)
7289 s = bc_vm_file(vm, *((char **) bc_vec_item(&vm->files, i)));
7290 if (s && s != BC_STATUS_QUIT) return s;
7292 if (IS_BC || !vm->files.len) s = bc_vm_stdin(vm);
7293 if (!s && !BC_PARSE_CAN_EXEC(&vm->prs)) s = bc_vm_process(vm, "");
7295 if (s == BC_STATUS_QUIT)
7296 s = BC_STATUS_SUCCESS;
7300 static void bc_vm_free(BcVm *vm)
7302 bc_vec_free(&vm->files);
7303 bc_program_free(&vm->prog);
7304 bc_parse_free(&vm->prs);
7308 static BcStatus bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len)
7310 BcStatus s = BC_STATUS_SUCCESS;
7311 size_t len = bc_vm_envLen(env_len);
7312 #if ENABLE_FEATURE_BC_SIGNALS
7313 struct sigaction sa;
7315 sigemptyset(&sa.sa_mask);
7316 sa.sa_handler = bc_vm_sig;
7318 sigaction(SIGINT, &sa, NULL);
7321 memset(vm, 0, sizeof(BcVm));
7325 vm->env_args = NULL;
7327 bc_vec_init(&vm->files, sizeof(char *), NULL);
7330 vm->flags |= BC_FLAG_S * IS_BC * (getenv("POSIXLY_CORRECT") != NULL);
7331 if (IS_BC) s = bc_vm_envArgs(vm);
7334 bc_program_init(&vm->prog, len, exe.init, exe.exp);
7335 exe.init(&vm->prs, &vm->prog, BC_PROG_MAIN);
7340 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
7341 const char *env_len)
7346 st = bc_vm_init(&vm, exe, env_len);
7348 st = bc_args(argc, argv, &vm.flags, &vm.files);
7351 bcg.ttyin = isatty(0);
7352 bcg.tty = bcg.ttyin || (vm.flags & BC_FLAG_I) || isatty(1);
7355 bcg.posix = vm.flags & BC_FLAG_S;
7356 bcg.warn = vm.flags & BC_FLAG_W;
7359 bcg.exreg = vm.flags & BC_FLAG_X;
7362 if (bcg.ttyin && !(vm.flags & BC_FLAG_Q)) bc_vm_info();
7363 st = bc_vm_exec(&vm);
7371 BcStatus bc_main(int argc, char *argv[])
7375 # if ENABLE_FEATURE_BC_SIGNALS
7376 bcg.sig_msg = bc_sig_msg;
7379 exec.init = bc_parse_init;
7380 exec.exp = bc_parse_expression;
7381 exec.sbgn = exec.send = '"';
7383 return bc_vm_run(argc, argv, exec, "BC_LINE_LENGTH");
7388 BcStatus dc_main(int argc, char *argv[])
7392 # if ENABLE_FEATURE_BC_SIGNALS
7393 bcg.sig_msg = dc_sig_msg;
7396 exec.init = dc_parse_init;
7397 exec.exp = dc_parse_expr;
7401 return bc_vm_run(argc, argv, exec, "DC_LINE_LENGTH");