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 *);
253 typedef struct BcVec {
261 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
262 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
264 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
266 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
268 typedef signed char BcDig;
270 typedef struct BcNum {
278 #define BC_NUM_MIN_BASE ((unsigned long) 2)
279 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
280 #define BC_NUM_DEF_SIZE (16)
281 #define BC_NUM_PRINT_WIDTH (69)
283 #define BC_NUM_KARATSUBA_LEN (32)
285 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
286 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
287 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
288 #define BC_NUM_AREQ(a, b) \
289 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
290 #define BC_NUM_MREQ(a, b, scale) \
291 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
293 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
294 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
296 static void bc_num_init(BcNum *n, size_t req);
297 static void bc_num_expand(BcNum *n, size_t req);
298 static void bc_num_copy(BcNum *d, BcNum *s);
299 static void bc_num_free(void *num);
301 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
302 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val);
304 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
305 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
308 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
309 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
310 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
311 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
314 typedef enum BcInst {
344 BC_INST_ASSIGN_POWER,
345 BC_INST_ASSIGN_MULTIPLY,
346 BC_INST_ASSIGN_DIVIDE,
347 BC_INST_ASSIGN_MODULUS,
349 BC_INST_ASSIGN_MINUS,
395 BC_INST_PRINT_STREAM,
410 BC_INST_INVALID = -1,
415 typedef struct BcId {
420 typedef struct BcFunc {
427 typedef enum BcResultType {
432 BC_RESULT_ARRAY_ELEM,
441 // These are between to calculate ibase, obase, and last from instructions.
449 typedef union BcResultData {
455 typedef struct BcResult {
460 typedef struct BcInstPtr {
466 static void bc_array_expand(BcVec *a, size_t len);
467 static int bc_id_cmp(const void *e1, const void *e2);
469 // BC_LEX_NEG is not used in lexing; it is only for parsing.
470 typedef enum BcLexType {
498 BC_LEX_OP_ASSIGN_POWER,
499 BC_LEX_OP_ASSIGN_MULTIPLY,
500 BC_LEX_OP_ASSIGN_DIVIDE,
501 BC_LEX_OP_ASSIGN_MODULUS,
502 BC_LEX_OP_ASSIGN_PLUS,
503 BC_LEX_OP_ASSIGN_MINUS,
577 typedef BcStatus (*BcLexNext)(struct BcLex *);
579 typedef struct BcLex {
598 #define BC_PARSE_STREND ((char) UCHAR_MAX)
600 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
601 #define bc_parse_updateFunc(p, f) \
602 ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f))))
604 #define BC_PARSE_REL (1 << 0)
605 #define BC_PARSE_PRINT (1 << 1)
606 #define BC_PARSE_NOCALL (1 << 2)
607 #define BC_PARSE_NOREAD (1 << 3)
608 #define BC_PARSE_ARRAY (1 << 4)
610 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
611 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
613 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
614 #define BC_PARSE_FUNC_INNER(parse) \
615 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
617 #define BC_PARSE_FLAG_FUNC (1 << 1)
618 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
620 #define BC_PARSE_FLAG_BODY (1 << 2)
621 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
623 #define BC_PARSE_FLAG_LOOP (1 << 3)
624 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
626 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
627 #define BC_PARSE_LOOP_INNER(parse) \
628 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
630 #define BC_PARSE_FLAG_IF (1 << 5)
631 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
633 #define BC_PARSE_FLAG_ELSE (1 << 6)
634 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
636 #define BC_PARSE_FLAG_IF_END (1 << 7)
637 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
639 #define BC_PARSE_CAN_EXEC(parse) \
640 (!(BC_PARSE_TOP_FLAG(parse) & \
641 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
642 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
643 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
645 typedef struct BcOp {
650 typedef struct BcParseNext {
655 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
656 #define BC_PARSE_NEXT(a, ...) \
658 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
665 typedef void (*BcParseInit)(struct BcParse *, struct BcProgram *, size_t);
666 typedef BcStatus (*BcParseParse)(struct BcParse *);
667 typedef BcStatus (*BcParseExpr)(struct BcParse *, uint8_t);
669 typedef struct BcParse {
682 struct BcProgram *prog;
693 typedef struct BcLexKeyword {
699 #define BC_LEX_KW_ENTRY(a, b, c) \
701 .name = a, .len = (b), .posix = (c) \
704 static BcStatus bc_lex_token(BcLex *l);
706 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
707 #define BC_PARSE_LEAF(p, rparen) \
708 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
709 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
711 // We can calculate the conversion between tokens and exprs by subtracting the
712 // position of the first operator in the lex enum and adding the position of the
713 // first in the expr enum. Note: This only works for binary operators.
714 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
716 static BcStatus bc_parse_parse(BcParse *p);
717 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
723 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
725 static BcStatus dc_lex_token(BcLex *l);
727 static void dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
728 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
732 typedef struct BcProgram {
771 BcParseInit parse_init;
772 BcParseExpr parse_expr;
776 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
778 #define BC_PROG_MAIN (0)
779 #define BC_PROG_READ (1)
782 #define BC_PROG_REQ_FUNCS (2)
785 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
786 #define BC_PROG_NUM(r, n) \
787 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
789 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
791 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx);
792 static BcStatus bc_program_reset(BcProgram *p, BcStatus s);
793 static BcStatus bc_program_exec(BcProgram *p);
795 #define BC_FLAG_X (1 << 0)
796 #define BC_FLAG_W (1 << 1)
797 #define BC_FLAG_V (1 << 2)
798 #define BC_FLAG_S (1 << 3)
799 #define BC_FLAG_Q (1 << 4)
800 #define BC_FLAG_L (1 << 5)
801 #define BC_FLAG_I (1 << 6)
803 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
804 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
806 #define BC_MAX_OBASE ((unsigned long) 999)
807 #define BC_MAX_DIM ((unsigned long) INT_MAX)
808 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
809 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
810 #define BC_MAX_NAME BC_MAX_STRING
811 #define BC_MAX_NUM BC_MAX_STRING
812 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
813 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
815 typedef struct BcVmExe {
822 typedef struct BcVm {
835 typedef struct BcGlobals {
847 #if ENABLE_FEATURE_BC_SIGNALS
854 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
857 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
861 static void bc_vm_info(void);
863 static BcGlobals bcg;
865 static const char* const bc_args_env_name = "BC_ENV_ARGS";
867 static const char bc_err_fmt[] = "\n%s error: %s\n";
868 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
869 static const char bc_err_line[] = ":%zu\n\n";
871 static const char *bc_errs[] = {
883 static const uint8_t bc_err_ids[] = {
884 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
885 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
889 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
890 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
891 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
896 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
897 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
898 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
899 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
901 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
903 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
904 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
905 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
907 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
910 static const char *bc_err_msgs[] = {
913 "memory allocation error",
916 "path is a directory:",
919 "string end could not be found",
920 "comment end could not be found",
929 "bad print statement",
930 "bad function definition",
931 "bad assignment: left side must be scale, ibase, "
932 "obase, last, var, or array element",
933 "no auto variable found",
934 "function parameter or auto var has the same name as another",
935 "block end could not be found",
938 "non integer number",
943 "could not open file:",
944 "mismatched parameters",
945 "undefined function",
946 "file is not executable:",
947 "number too long: must be [1, BC_NUM_MAX]",
948 "name too long: must be [1, BC_NAME_MAX]",
949 "string too long: must be [1, BC_STRING_MAX]",
950 "array too long; must be [1, BC_DIM_MAX]",
951 "bad ibase; must be [2, 16]",
952 "bad scale; must be [0, BC_SCALE_MAX]",
953 "bad read() expression",
954 "read() call inside of a read() call",
955 "variable is wrong type",
956 "bad obase; must be [2, BC_BASE_MAX]",
957 "signal caught and not handled",
958 "stack has too few elements",
960 "index is out of bounds",
961 "item already exists",
964 "POSIX only allows one character names; the following is bad:",
965 "POSIX does not allow '#' script comments",
966 "POSIX does not allow the following keyword:",
967 "POSIX does not allow a period ('.') as a shortcut for the last result",
968 "POSIX requires parentheses around return expressions",
969 "POSIX does not allow boolean operators; the following is bad:",
970 "POSIX does not allow comparison operators outside if or loops",
971 "POSIX requires exactly one comparison operator per condition",
972 "POSIX does not allow an empty init expression in a for loop",
973 "POSIX does not allow an empty condition expression in a for loop",
974 "POSIX does not allow an empty update expression in a for loop",
975 "POSIX requires the left brace be on the same line as the function header",
980 static const char bc_func_main[] = "(main)";
981 static const char bc_func_read[] = "(read)";
984 static const BcLexKeyword bc_lex_kws[20] = {
985 BC_LEX_KW_ENTRY("auto", 4, true),
986 BC_LEX_KW_ENTRY("break", 5, true),
987 BC_LEX_KW_ENTRY("continue", 8, false),
988 BC_LEX_KW_ENTRY("define", 6, true),
989 BC_LEX_KW_ENTRY("else", 4, false),
990 BC_LEX_KW_ENTRY("for", 3, true),
991 BC_LEX_KW_ENTRY("halt", 4, false),
992 BC_LEX_KW_ENTRY("ibase", 5, true),
993 BC_LEX_KW_ENTRY("if", 2, true),
994 BC_LEX_KW_ENTRY("last", 4, false),
995 BC_LEX_KW_ENTRY("length", 6, true),
996 BC_LEX_KW_ENTRY("limits", 6, false),
997 BC_LEX_KW_ENTRY("obase", 5, true),
998 BC_LEX_KW_ENTRY("print", 5, false),
999 BC_LEX_KW_ENTRY("quit", 4, true),
1000 BC_LEX_KW_ENTRY("read", 4, false),
1001 BC_LEX_KW_ENTRY("return", 6, true),
1002 BC_LEX_KW_ENTRY("scale", 5, true),
1003 BC_LEX_KW_ENTRY("sqrt", 4, true),
1004 BC_LEX_KW_ENTRY("while", 5, true),
1007 // This is an array that corresponds to token types. An entry is
1008 // true if the token is valid in an expression, false otherwise.
1009 static const bool bc_parse_exprs[] = {
1010 false, false, true, true, true, true, true, true, true, true, true, true,
1011 true, true, true, true, true, true, true, true, true, true, true, true,
1012 true, true, true, false, false, true, true, false, false, false, false,
1013 false, false, false, true, true, false, false, false, false, false, false,
1014 false, true, false, true, true, true, true, false, false, true, false, true,
1018 // This is an array of data for operators that correspond to token types.
1019 static const BcOp bc_parse_ops[] = {
1020 { 0, false }, { 0, false },
1023 { 3, true }, { 3, true }, { 3, true },
1024 { 4, true }, { 4, true },
1025 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1027 { 7, true }, { 7, true },
1028 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1029 { 5, false }, { 5, false },
1032 // These identify what tokens can come after expressions in certain cases.
1033 static const BcParseNext bc_parse_next_expr =
1034 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1035 static const BcParseNext bc_parse_next_param =
1036 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1037 static const BcParseNext bc_parse_next_print =
1038 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1039 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1040 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1041 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1042 static const BcParseNext bc_parse_next_read =
1043 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1047 static const BcLexType dc_lex_regs[] = {
1048 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1049 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1050 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1054 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1056 static const BcLexType dc_lex_tokens[] = {
1057 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1058 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1059 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1060 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1061 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1062 BC_LEX_INVALID, BC_LEX_INVALID,
1063 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1064 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1065 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1066 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1067 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1068 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1069 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1070 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1071 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1072 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1073 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1074 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1075 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1076 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1077 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1078 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1079 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1080 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1084 static const BcInst dc_parse_insts[] = {
1085 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1086 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1087 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1088 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1089 BC_INST_INVALID, BC_INST_INVALID,
1090 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1091 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1092 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1093 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1094 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1095 BC_INST_INVALID, BC_INST_INVALID,
1096 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1097 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1098 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1099 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1100 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1101 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1102 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1103 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1104 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1105 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1106 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1107 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1111 static const BcNumBinaryOp bc_program_ops[] = {
1112 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1115 static const char bc_program_stdin_name[] = "<stdin>";
1116 static const char bc_program_ready_msg[] = "ready for more input\n";
1119 static const char *bc_lib_name = "gen/lib.bc";
1121 static const char bc_lib[] = {
1122 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1123 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1124 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1125 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,
1126 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1127 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1128 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,
1129 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1130 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1131 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,
1132 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1133 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1134 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1135 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1136 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1137 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1138 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1139 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1140 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1141 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1142 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1143 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1144 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1145 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,
1146 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1147 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,
1148 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1149 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1150 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1151 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1152 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1153 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,
1154 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1155 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1156 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1157 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1158 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,
1159 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1160 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1161 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1162 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1163 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1164 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1165 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1166 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1167 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1168 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1169 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,
1170 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,
1171 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1172 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,
1173 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,
1174 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,
1175 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1176 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1177 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,
1178 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,
1179 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,
1180 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1181 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,
1182 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1183 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1184 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1185 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,
1186 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1187 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1188 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1189 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1190 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1191 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1192 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1193 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1194 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1195 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1196 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1197 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1198 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1199 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1200 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1201 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1205 static void bc_vec_grow(BcVec *v, size_t n)
1207 size_t cap = v->cap * 2;
1208 while (cap < v->len + n) cap *= 2;
1209 v->v = xrealloc(v->v, v->size * cap);
1213 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1216 v->cap = BC_VEC_START_CAP;
1219 v->v = xmalloc(esize * BC_VEC_START_CAP);
1222 static void bc_vec_expand(BcVec *v, size_t req)
1225 v->v = xrealloc(v->v, v->size * req);
1230 static void bc_vec_npop(BcVec *v, size_t n)
1235 size_t len = v->len - n;
1236 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1240 static void bc_vec_push(BcVec *v, const void *data)
1242 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1243 memmove(v->v + (v->size * v->len), data, v->size);
1247 static void bc_vec_pushByte(BcVec *v, char data)
1249 bc_vec_push(v, &data);
1252 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1255 bc_vec_push(v, data);
1260 if (v->len == v->cap) bc_vec_grow(v, 1);
1262 ptr = v->v + v->size * idx;
1264 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1265 memmove(ptr, data, v->size);
1269 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1271 bc_vec_npop(v, v->len);
1272 bc_vec_expand(v, len + 1);
1273 memcpy(v->v, str, len);
1276 bc_vec_pushByte(v, '\0');
1279 static void bc_vec_concat(BcVec *v, const char *str)
1283 if (v->len == 0) bc_vec_pushByte(v, '\0');
1285 len = v->len + strlen(str);
1287 if (v->cap < len) bc_vec_grow(v, len - v->len);
1293 static void *bc_vec_item(const BcVec *v, size_t idx)
1295 return v->v + v->size * idx;
1298 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1300 return v->v + v->size * (v->len - idx - 1);
1303 static void bc_vec_free(void *vec)
1305 BcVec *v = (BcVec *) vec;
1306 bc_vec_npop(v, v->len);
1310 static size_t bc_map_find(const BcVec *v, const void *ptr)
1312 size_t low = 0, high = v->len;
1314 while (low < high) {
1316 size_t mid = (low + high) / 2;
1317 BcId *id = bc_vec_item(v, mid);
1318 int result = bc_id_cmp(ptr, id);
1322 else if (result < 0)
1331 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1333 BcStatus s = BC_STATUS_SUCCESS;
1335 *i = bc_map_find(v, ptr);
1338 bc_vec_push(v, ptr);
1339 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1340 s = BC_STATUS_VEC_ITEM_EXISTS;
1342 bc_vec_pushAt(v, ptr, *i);
1347 static size_t bc_map_index(const BcVec *v, const void *ptr)
1349 size_t i = bc_map_find(v, ptr);
1350 if (i >= v->len) return BC_VEC_INVALID_IDX;
1351 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1354 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1359 if (bcg.ttyin && !bcg.posix) {
1360 fputs(prompt, stderr);
1364 bc_vec_npop(vec, vec->len);
1367 if (ferror(stdout) || ferror(stderr))
1368 bb_perror_msg_and_die("output error");
1374 #if ENABLE_FEATURE_BC_SIGNALS
1375 if (errno == EINTR) {
1379 fputs(bc_program_ready_msg, stderr);
1380 if (!bcg.posix) fputs(prompt, stderr);
1387 bb_perror_msg_and_die("input error");
1389 return BC_STATUS_INPUT_EOF;
1392 c = (signed char) i;
1393 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1394 bc_vec_push(vec, &c);
1395 } while (c != '\n');
1397 bc_vec_pushByte(vec, '\0');
1399 return BC_STATUS_SUCCESS;
1402 static BcStatus bc_read_file(const char *path, char **buf)
1404 BcStatus s = BC_STATUS_BIN_FILE;
1405 size_t size = ((size_t) -1);
1408 *buf = xmalloc_open_read_close(path, &size);
1410 for (i = 0; i < size; ++i) {
1411 if (BC_READ_BIN_CHAR((*buf)[i]))
1415 return BC_STATUS_SUCCESS;
1422 static void bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
1425 bool do_exit = false;
1428 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1429 *flags = getopt32long(argv, "xwvsqli",
1430 "extended-register\0" No_argument "x"
1431 "warn\0" No_argument "w"
1432 "version\0" No_argument "v"
1433 "standard\0" No_argument "s"
1434 "quiet\0" No_argument "q"
1435 "mathlib\0" No_argument "l"
1436 "interactive\0" No_argument "i"
1439 *flags = getopt32(argv, "xwvsqli");
1442 if ((*flags) & BC_FLAG_V) bc_vm_info();
1443 if (do_exit) exit(0);
1444 // should not be necessary, getopt32() handles this??
1445 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1447 for (i = optind; i < argc; ++i) bc_vec_push(files, argv + i);
1450 static void bc_num_setToZero(BcNum *n, size_t scale)
1457 static void bc_num_zero(BcNum *n)
1459 bc_num_setToZero(n, 0);
1462 static void bc_num_one(BcNum *n)
1464 bc_num_setToZero(n, 0);
1469 static void bc_num_ten(BcNum *n)
1471 bc_num_setToZero(n, 0);
1477 static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1481 for (i = 0; !bcg.signe && i < len; ++i) {
1482 for (a[i] -= b[i], j = 0; !bcg.signe && a[i + j] < 0;) {
1487 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1490 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1494 for (i = len - 1; !bcg.signe && i < len && !(c = a[i] - b[i]); --i);
1495 return BC_NUM_NEG(i + 1, c < 0);
1498 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1500 size_t i, min, a_int, b_int, diff;
1501 BcDig *max_num, *min_num;
1502 bool a_max, neg = false;
1505 if (a == b) return 0;
1506 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1507 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1517 a_int = BC_NUM_INT(a);
1518 b_int = BC_NUM_INT(b);
1520 a_max = (a->rdx > b->rdx);
1522 if (a_int != 0) return (ssize_t) a_int;
1526 diff = a->rdx - b->rdx;
1527 max_num = a->num + diff;
1532 diff = b->rdx - a->rdx;
1533 max_num = b->num + diff;
1537 cmp = bc_num_compare(max_num, min_num, b_int + min);
1538 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1540 for (max_num -= diff, i = diff - 1; !bcg.signe && i < diff; --i) {
1541 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1547 static void bc_num_truncate(BcNum *n, size_t places)
1549 if (places == 0) return;
1555 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1559 static void bc_num_extend(BcNum *n, size_t places)
1561 size_t len = n->len + places;
1565 if (n->cap < len) bc_num_expand(n, len);
1567 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1568 memset(n->num, 0, sizeof(BcDig) * places);
1575 static void bc_num_clean(BcNum *n)
1577 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1580 else if (n->len < n->rdx)
1584 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1587 bc_num_extend(n, scale - n->rdx);
1589 bc_num_truncate(n, n->rdx - scale);
1592 if (n->len != 0) n->neg = !neg1 != !neg2;
1595 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1600 b->len = n->len - idx;
1602 a->rdx = b->rdx = 0;
1604 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1605 memcpy(a->num, n->num, idx * sizeof(BcDig));
1616 static BcStatus bc_num_shift(BcNum *n, size_t places)
1618 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1619 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1621 if (n->rdx >= places)
1624 bc_num_extend(n, places - n->rdx);
1630 return BC_STATUS_SUCCESS;
1633 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1642 return bc_num_div(&one, a, b, scale);
1645 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1647 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1648 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1651 // Because this function doesn't need to use scale (per the bc spec),
1652 // I am hijacking it to say whether it's doing an add or a subtract.
1656 if (sub && c->len) c->neg = !c->neg;
1657 return BC_STATUS_SUCCESS;
1659 else if (b->len == 0) {
1661 return BC_STATUS_SUCCESS;
1665 c->rdx = BC_MAX(a->rdx, b->rdx);
1666 min_rdx = BC_MIN(a->rdx, b->rdx);
1669 if (a->rdx > b->rdx) {
1670 diff = a->rdx - b->rdx;
1672 ptr_a = a->num + diff;
1676 diff = b->rdx - a->rdx;
1679 ptr_b = b->num + diff;
1682 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1685 a_int = BC_NUM_INT(a);
1686 b_int = BC_NUM_INT(b);
1688 if (a_int > b_int) {
1699 for (carry = 0, i = 0; !bcg.signe && i < min_rdx + min_int; ++i, ++c->len) {
1700 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1702 ptr_c[i] = (BcDig)(in % 10);
1705 for (; !bcg.signe && i < max + min_rdx; ++i, ++c->len) {
1706 in = ((int) ptr[i]) + carry;
1708 ptr_c[i] = (BcDig)(in % 10);
1711 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1713 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1716 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1720 BcNum *minuend, *subtrahend;
1722 bool aneg, bneg, neg;
1724 // Because this function doesn't need to use scale (per the bc spec),
1725 // I am hijacking it to say whether it's doing an add or a subtract.
1729 if (sub && c->len) c->neg = !c->neg;
1730 return BC_STATUS_SUCCESS;
1732 else if (b->len == 0) {
1734 return BC_STATUS_SUCCESS;
1739 a->neg = b->neg = false;
1741 cmp = bc_num_cmp(a, b);
1747 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1748 return BC_STATUS_SUCCESS;
1757 if (sub) neg = !neg;
1762 bc_num_copy(c, minuend);
1765 if (c->rdx < subtrahend->rdx) {
1766 bc_num_extend(c, subtrahend->rdx - c->rdx);
1770 start = c->rdx - subtrahend->rdx;
1772 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1779 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1784 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1785 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1786 bool aone = BC_NUM_ONE(a);
1788 if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
1789 if (a->len == 0 || b->len == 0) {
1791 return BC_STATUS_SUCCESS;
1793 else if (aone || BC_NUM_ONE(b)) {
1794 bc_num_copy(c, aone ? b : a);
1795 return BC_STATUS_SUCCESS;
1798 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1799 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1801 bc_num_expand(c, a->len + b->len + 1);
1803 memset(c->num, 0, sizeof(BcDig) * c->cap);
1804 c->len = carry = len = 0;
1806 for (i = 0; !bcg.signe && i < b->len; ++i) {
1808 for (j = 0; !bcg.signe && j < a->len; ++j) {
1809 int in = (int) c->num[i + j];
1810 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1812 c->num[i + j] = (BcDig)(in % 10);
1815 c->num[i + j] += (BcDig) carry;
1816 len = BC_MAX(len, i + j + !!carry);
1822 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1825 bc_num_init(&l1, max);
1826 bc_num_init(&h1, max);
1827 bc_num_init(&l2, max);
1828 bc_num_init(&h2, max);
1829 bc_num_init(&m1, max);
1830 bc_num_init(&m2, max);
1831 bc_num_init(&z0, max);
1832 bc_num_init(&z1, max);
1833 bc_num_init(&z2, max);
1834 bc_num_init(&temp, max + max);
1836 bc_num_split(a, max2, &l1, &h1);
1837 bc_num_split(b, max2, &l2, &h2);
1839 s = bc_num_add(&h1, &l1, &m1, 0);
1841 s = bc_num_add(&h2, &l2, &m2, 0);
1844 s = bc_num_k(&h1, &h2, &z0);
1846 s = bc_num_k(&m1, &m2, &z1);
1848 s = bc_num_k(&l1, &l2, &z2);
1851 s = bc_num_sub(&z1, &z0, &temp, 0);
1853 s = bc_num_sub(&temp, &z2, &z1, 0);
1856 s = bc_num_shift(&z0, max2 * 2);
1858 s = bc_num_shift(&z1, max2);
1860 s = bc_num_add(&z0, &z1, &temp, 0);
1862 s = bc_num_add(&temp, &z2, c, 0);
1878 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1882 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1884 scale = BC_MAX(scale, a->rdx);
1885 scale = BC_MAX(scale, b->rdx);
1886 scale = BC_MIN(a->rdx + b->rdx, scale);
1887 maxrdx = BC_MAX(maxrdx, scale);
1889 bc_num_init(&cpa, a->len);
1890 bc_num_init(&cpb, b->len);
1892 bc_num_copy(&cpa, a);
1893 bc_num_copy(&cpb, b);
1894 cpa.neg = cpb.neg = false;
1896 s = bc_num_shift(&cpa, maxrdx);
1898 s = bc_num_shift(&cpb, maxrdx);
1900 s = bc_num_k(&cpa, &cpb, c);
1904 bc_num_expand(c, c->len + maxrdx);
1906 if (c->len < maxrdx) {
1907 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1912 bc_num_retireMul(c, scale, a->neg, b->neg);
1920 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1922 BcStatus s = BC_STATUS_SUCCESS;
1929 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1930 else if (a->len == 0) {
1931 bc_num_setToZero(c, scale);
1932 return BC_STATUS_SUCCESS;
1934 else if (BC_NUM_ONE(b)) {
1936 bc_num_retireMul(c, scale, a->neg, b->neg);
1937 return BC_STATUS_SUCCESS;
1940 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1941 bc_num_copy(&cp, a);
1945 bc_num_expand(&cp, len + 2);
1946 bc_num_extend(&cp, len - cp.len);
1949 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1951 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1953 if (b->rdx == b->len) {
1954 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1958 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1960 // We want an extra zero in front to make things simpler.
1961 cp.num[cp.len++] = 0;
1964 bc_num_expand(c, cp.len);
1967 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1972 for (i = end - 1; !bcg.signe && !s && i < end; --i) {
1974 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1975 s = bc_num_subArrays(n, p, len);
1979 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
1985 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1986 BcNum *restrict d, size_t scale, size_t ts)
1992 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1995 bc_num_setToZero(d, ts);
1996 return BC_STATUS_SUCCESS;
1999 bc_num_init(&temp, d->cap);
2000 bc_num_d(a, b, c, scale);
2002 if (scale != 0) scale = ts;
2004 s = bc_num_m(c, b, &temp, scale);
2006 s = bc_num_sub(a, &temp, d, scale);
2009 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2012 bc_num_retireMul(d, ts, a->neg, b->neg);
2020 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2024 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2026 bc_num_init(&c1, len);
2027 s = bc_num_r(a, b, &c1, c, scale, ts);
2033 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2035 BcStatus s = BC_STATUS_SUCCESS;
2038 size_t i, powrdx, resrdx;
2041 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2045 return BC_STATUS_SUCCESS;
2047 else if (a->len == 0) {
2048 bc_num_setToZero(c, scale);
2049 return BC_STATUS_SUCCESS;
2051 else if (BC_NUM_ONE(b)) {
2055 s = bc_num_inv(a, c, scale);
2062 s = bc_num_ulong(b, &pow);
2065 bc_num_init(©, a->len);
2066 bc_num_copy(©, a);
2068 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2072 for (powrdx = a->rdx; !bcg.signe && !(pow & 1); pow >>= 1) {
2074 s = bc_num_mul(©, ©, ©, powrdx);
2079 s = BC_STATUS_EXEC_SIGNAL;
2083 bc_num_copy(c, ©);
2085 for (resrdx = powrdx, pow >>= 1; !bcg.signe && pow != 0; pow >>= 1) {
2088 s = bc_num_mul(©, ©, ©, powrdx);
2093 s = bc_num_mul(c, ©, c, resrdx);
2099 s = bc_num_inv(c, c, scale);
2104 s = BC_STATUS_EXEC_SIGNAL;
2108 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2110 // We can't use bc_num_clean() here.
2111 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2112 if (zero) bc_num_setToZero(c, scale);
2119 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2120 BcNumBinaryOp op, size_t req)
2123 BcNum num2, *ptr_a, *ptr_b;
2128 memcpy(ptr_a, c, sizeof(BcNum));
2137 memcpy(ptr_b, c, sizeof(BcNum));
2145 bc_num_init(c, req);
2147 bc_num_expand(c, req);
2149 s = op(ptr_a, ptr_b, c, scale);
2151 if (init) bc_num_free(&num2);
2156 static bool bc_num_strValid(const char *val, size_t base)
2159 bool small, radix = false;
2160 size_t i, len = strlen(val);
2162 if (!len) return true;
2165 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2167 for (i = 0; i < len; ++i) {
2173 if (radix) return false;
2179 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2186 static void bc_num_parseDecimal(BcNum *n, const char *val)
2192 for (i = 0; val[i] == '0'; ++i);
2199 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2200 bc_num_expand(n, len);
2203 ptr = strchr(val, '.');
2205 // Explicitly test for NULL here to produce either a 0 or 1.
2206 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2209 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2210 n->num[n->len] = val[i] - '0';
2214 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2217 BcNum temp, mult, result;
2221 size_t i, digits, len = strlen(val);
2225 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2228 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2229 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2231 for (i = 0; i < len; ++i) {
2234 if (c == '.') break;
2236 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2238 s = bc_num_mul(n, base, &mult, 0);
2239 if (s) goto int_err;
2240 s = bc_num_ulong2num(&temp, v);
2241 if (s) goto int_err;
2242 s = bc_num_add(&mult, &temp, n, 0);
2243 if (s) goto int_err;
2248 if (c == 0) goto int_err;
2251 bc_num_init(&result, base->len);
2252 bc_num_zero(&result);
2255 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2260 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2262 s = bc_num_mul(&result, base, &result, 0);
2264 s = bc_num_ulong2num(&temp, v);
2266 s = bc_num_add(&result, &temp, &result, 0);
2268 s = bc_num_mul(&mult, base, &mult, 0);
2272 s = bc_num_div(&result, &mult, &result, digits);
2274 s = bc_num_add(n, &result, n, digits);
2278 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2284 bc_num_free(&result);
2290 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2292 if (*nchars == line_len - 1) {
2300 static void bc_num_printChar(size_t num, size_t width, bool radix,
2301 size_t *nchars, size_t line_len)
2303 (void) radix, (void) line_len;
2304 bb_putchar((char) num);
2305 *nchars = *nchars + width;
2309 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2310 size_t *nchars, size_t line_len)
2314 bc_num_printNewline(nchars, line_len);
2315 bb_putchar(radix ? '.' : ' ');
2318 bc_num_printNewline(nchars, line_len);
2319 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2322 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2324 bc_num_printNewline(nchars, line_len);
2327 bb_putchar(((char) dig) + '0');
2331 static void bc_num_printHex(size_t num, size_t width, bool radix,
2332 size_t *nchars, size_t line_len)
2335 bc_num_printNewline(nchars, line_len);
2340 bc_num_printNewline(nchars, line_len);
2341 bb_putchar(bb_hexdigits_upcase[num]);
2342 *nchars = *nchars + width;
2345 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2347 size_t i, rdx = n->rdx - 1;
2349 if (n->neg) bb_putchar('-');
2350 (*nchars) += n->neg;
2352 for (i = n->len - 1; i < n->len; --i)
2353 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2356 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2357 size_t *nchars, size_t len, BcNumDigitOp print)
2361 BcNum intp, fracp, digit, frac_len;
2362 unsigned long dig, *ptr;
2367 print(0, width, false, nchars, len);
2368 return BC_STATUS_SUCCESS;
2371 bc_vec_init(&stack, sizeof(long), NULL);
2372 bc_num_init(&intp, n->len);
2373 bc_num_init(&fracp, n->rdx);
2374 bc_num_init(&digit, width);
2375 bc_num_init(&frac_len, BC_NUM_INT(n));
2376 bc_num_copy(&intp, n);
2377 bc_num_one(&frac_len);
2379 bc_num_truncate(&intp, intp.rdx);
2380 s = bc_num_sub(n, &intp, &fracp, 0);
2383 while (intp.len != 0) {
2384 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2386 s = bc_num_ulong(&digit, &dig);
2388 bc_vec_push(&stack, &dig);
2391 for (i = 0; i < stack.len; ++i) {
2392 ptr = bc_vec_item_rev(&stack, i);
2393 print(*ptr, width, false, nchars, len);
2396 if (!n->rdx) goto err;
2398 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2399 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2401 s = bc_num_ulong(&fracp, &dig);
2403 s = bc_num_ulong2num(&intp, dig);
2405 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2407 print(dig, width, radix, nchars, len);
2408 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2413 bc_num_free(&frac_len);
2414 bc_num_free(&digit);
2415 bc_num_free(&fracp);
2417 bc_vec_free(&stack);
2421 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2422 size_t *nchars, size_t line_len)
2429 if (neg) bb_putchar('-');
2434 if (base_t <= BC_NUM_MAX_IBASE) {
2436 print = bc_num_printHex;
2439 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2440 print = bc_num_printDigits;
2443 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2450 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2452 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2456 static void bc_num_init(BcNum *n, size_t req)
2458 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2459 memset(n, 0, sizeof(BcNum));
2460 n->num = xmalloc(req);
2464 static void bc_num_expand(BcNum *n, size_t req)
2466 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2468 n->num = xrealloc(n->num, req);
2473 static void bc_num_free(void *num)
2475 free(((BcNum *) num)->num);
2478 static void bc_num_copy(BcNum *d, BcNum *s)
2481 bc_num_expand(d, s->cap);
2485 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2489 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2492 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2495 bc_num_parseDecimal(n, val);
2497 bc_num_parseBase(n, val, base);
2499 return BC_STATUS_SUCCESS;
2502 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2503 size_t *nchars, size_t line_len)
2505 BcStatus s = BC_STATUS_SUCCESS;
2507 bc_num_printNewline(nchars, line_len);
2513 else if (base_t == 10)
2514 bc_num_printDecimal(n, nchars, line_len);
2516 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2526 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2531 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2533 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2535 unsigned long prev = *result, powprev = pow;
2537 *result += ((unsigned long) n->num[i]) * pow;
2540 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2543 return BC_STATUS_SUCCESS;
2546 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val)
2554 if (val == 0) return BC_STATUS_SUCCESS;
2556 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2557 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2559 return BC_STATUS_SUCCESS;
2562 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2564 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2566 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2569 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2571 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2573 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2576 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2578 size_t req = BC_NUM_MREQ(a, b, scale);
2579 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2582 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2584 size_t req = BC_NUM_MREQ(a, b, scale);
2585 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2588 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2590 size_t req = BC_NUM_MREQ(a, b, scale);
2591 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2594 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2596 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2599 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2602 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2603 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2604 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2606 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2607 bc_num_expand(b, req);
2610 bc_num_setToZero(b, scale);
2611 return BC_STATUS_SUCCESS;
2614 return BC_STATUS_MATH_NEGATIVE;
2615 else if (BC_NUM_ONE(a)) {
2617 bc_num_extend(b, scale);
2618 return BC_STATUS_SUCCESS;
2621 scale = BC_MAX(scale, a->rdx) + 1;
2622 len = a->len + scale;
2624 bc_num_init(&num1, len);
2625 bc_num_init(&num2, len);
2626 bc_num_init(&half, BC_NUM_DEF_SIZE);
2632 bc_num_init(&f, len);
2633 bc_num_init(&fprime, len);
2639 pow = BC_NUM_INT(a);
2648 pow -= 2 - (pow & 1);
2650 bc_num_extend(x0, pow);
2652 // Make sure to move the radix back.
2656 x0->rdx = digs = digs1 = 0;
2658 len = BC_NUM_INT(x0) + resrdx - 1;
2660 while (!bcg.signe && (cmp != 0 || digs < len)) {
2662 s = bc_num_div(a, x0, &f, resrdx);
2664 s = bc_num_add(x0, &f, &fprime, resrdx);
2666 s = bc_num_mul(&fprime, &half, x1, resrdx);
2669 cmp = bc_num_cmp(x1, x0);
2670 digs = x1->len - (unsigned long long) llabs(cmp);
2672 if (cmp == cmp2 && digs == digs1)
2677 resrdx += times > 4;
2689 s = BC_STATUS_EXEC_SIGNAL;
2695 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2698 bc_num_free(&fprime);
2706 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2712 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2715 memcpy(&num2, c, sizeof(BcNum));
2717 bc_num_init(c, len);
2722 bc_num_expand(c, len);
2725 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2727 if (init) bc_num_free(&num2);
2733 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2736 BcNum base, exp, two, temp;
2738 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2739 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2740 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2742 bc_num_expand(d, c->len);
2743 bc_num_init(&base, c->len);
2744 bc_num_init(&exp, b->len);
2745 bc_num_init(&two, BC_NUM_DEF_SIZE);
2746 bc_num_init(&temp, b->len);
2752 s = bc_num_rem(a, c, &base, 0);
2754 bc_num_copy(&exp, b);
2756 while (exp.len != 0) {
2758 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2761 if (BC_NUM_ONE(&temp)) {
2762 s = bc_num_mul(d, &base, &temp, 0);
2764 s = bc_num_rem(&temp, c, d, 0);
2768 s = bc_num_mul(&base, &base, &temp, 0);
2770 s = bc_num_rem(&temp, c, &base, 0);
2783 static int bc_id_cmp(const void *e1, const void *e2)
2785 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2788 static void bc_id_free(void *id)
2790 free(((BcId *) id)->name);
2793 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2798 for (i = 0; i < f->autos.len; ++i) {
2799 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2800 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2806 bc_vec_push(&f->autos, &a);
2808 return BC_STATUS_SUCCESS;
2811 static void bc_func_init(BcFunc *f)
2813 bc_vec_init(&f->code, sizeof(char), NULL);
2814 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2815 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2819 static void bc_func_free(void *func)
2821 BcFunc *f = (BcFunc *) func;
2822 bc_vec_free(&f->code);
2823 bc_vec_free(&f->autos);
2824 bc_vec_free(&f->labels);
2827 static void bc_array_init(BcVec *a, bool nums)
2830 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2832 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2833 bc_array_expand(a, 1);
2836 static void bc_array_copy(BcVec *d, const BcVec *s)
2840 bc_vec_npop(d, d->len);
2841 bc_vec_expand(d, s->cap);
2844 for (i = 0; i < s->len; ++i) {
2845 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2846 bc_num_init(dnum, snum->len);
2847 bc_num_copy(dnum, snum);
2851 static void bc_array_expand(BcVec *a, size_t len)
2855 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2856 while (len > a->len) {
2857 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2858 bc_vec_push(a, &data.n);
2862 while (len > a->len) {
2863 bc_array_init(&data.v, true);
2864 bc_vec_push(a, &data.v);
2869 static void bc_string_free(void *string)
2871 free(*((char **) string));
2875 static void bc_result_copy(BcResult *d, BcResult *src)
2881 case BC_RESULT_TEMP:
2882 case BC_RESULT_IBASE:
2883 case BC_RESULT_SCALE:
2884 case BC_RESULT_OBASE:
2886 bc_num_init(&d->d.n, src->d.n.len);
2887 bc_num_copy(&d->d.n, &src->d.n);
2892 case BC_RESULT_ARRAY:
2893 case BC_RESULT_ARRAY_ELEM:
2895 d->d.id.name = xstrdup(src->d.id.name);
2899 case BC_RESULT_CONSTANT:
2900 case BC_RESULT_LAST:
2904 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2911 static void bc_result_free(void *result)
2913 BcResult *r = (BcResult *) result;
2917 case BC_RESULT_TEMP:
2918 case BC_RESULT_IBASE:
2919 case BC_RESULT_SCALE:
2920 case BC_RESULT_OBASE:
2922 bc_num_free(&r->d.n);
2927 case BC_RESULT_ARRAY:
2928 case BC_RESULT_ARRAY_ELEM:
2942 static void bc_lex_lineComment(BcLex *l)
2944 l->t.t = BC_LEX_WHITESPACE;
2945 while (l->i < l->len && l->buf[l->i++] != '\n');
2949 static void bc_lex_whitespace(BcLex *l)
2952 l->t.t = BC_LEX_WHITESPACE;
2953 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2956 static BcStatus bc_lex_number(BcLex *l, char start)
2958 const char *buf = l->buf + l->i;
2959 size_t len, hits = 0, bslashes = 0, i = 0, j;
2961 bool last_pt, pt = start == '.';
2964 l->t.t = BC_LEX_NUMBER;
2966 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2967 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2981 len = i + 1 * !last_pt - bslashes * 2;
2982 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2984 bc_vec_npop(&l->t.v, l->t.v.len);
2985 bc_vec_expand(&l->t.v, len + 1);
2986 bc_vec_push(&l->t.v, &start);
2988 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2992 // If we have hit a backslash, skip it. We don't have
2993 // to check for a newline because it's guaranteed.
2994 if (hits < bslashes && c == '\\') {
3000 bc_vec_push(&l->t.v, &c);
3003 bc_vec_pushByte(&l->t.v, '\0');
3006 return BC_STATUS_SUCCESS;
3009 static BcStatus bc_lex_name(BcLex *l)
3012 const char *buf = l->buf + l->i - 1;
3015 l->t.t = BC_LEX_NAME;
3017 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3019 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3020 bc_vec_string(&l->t.v, i, buf);
3022 // Increment the index. We minus 1 because it has already been incremented.
3025 return BC_STATUS_SUCCESS;
3028 static void bc_lex_init(BcLex *l, BcLexNext next)
3031 bc_vec_init(&l->t.v, sizeof(char), NULL);
3034 static void bc_lex_free(BcLex *l)
3036 bc_vec_free(&l->t.v);
3039 static void bc_lex_file(BcLex *l, const char *file)
3046 static BcStatus bc_lex_next(BcLex *l)
3051 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3053 l->line += l->newline;
3054 l->t.t = BC_LEX_EOF;
3056 l->newline = (l->i == l->len);
3057 if (l->newline) return BC_STATUS_SUCCESS;
3059 // Loop until failure or we don't have whitespace. This
3060 // is so the parser doesn't get inundated with whitespace.
3063 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3068 static BcStatus bc_lex_text(BcLex *l, const char *text)
3072 l->len = strlen(text);
3073 l->t.t = l->t.last = BC_LEX_INVALID;
3074 return bc_lex_next(l);
3078 static BcStatus bc_lex_identifier(BcLex *l)
3082 const char *buf = l->buf + l->i - 1;
3084 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3086 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3088 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3090 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3092 if (!bc_lex_kws[i].posix) {
3093 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3094 bc_lex_kws[i].name);
3098 // We minus 1 because the index has already been incremented.
3100 return BC_STATUS_SUCCESS;
3107 if (l->t.v.len - 1 > 1)
3108 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3113 static BcStatus bc_lex_string(BcLex *l)
3115 size_t len, nls = 0, i = l->i;
3118 l->t.t = BC_LEX_STR;
3120 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3124 return BC_STATUS_LEX_NO_STRING_END;
3128 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3129 bc_vec_string(&l->t.v, len, l->buf + l->i);
3134 return BC_STATUS_SUCCESS;
3137 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3139 if (l->buf[l->i] == '=') {
3147 static BcStatus bc_lex_comment(BcLex *l)
3150 const char *buf = l->buf;
3154 l->t.t = BC_LEX_WHITESPACE;
3156 for (i = ++l->i; !end; i += !end) {
3158 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3160 if (c == 0 || buf[i + 1] == '\0') {
3162 return BC_STATUS_LEX_NO_COMMENT_END;
3165 end = buf[i + 1] == '/';
3171 return BC_STATUS_SUCCESS;
3174 static BcStatus bc_lex_token(BcLex *l)
3176 BcStatus s = BC_STATUS_SUCCESS;
3177 char c = l->buf[l->i++], c2;
3179 // This is the workhorse of the lexer.
3186 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3196 bc_lex_whitespace(l);
3202 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3204 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3205 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3214 s = bc_lex_string(l);
3220 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3223 bc_lex_lineComment(l);
3230 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3239 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3243 l->t.t = BC_LEX_OP_BOOL_AND;
3246 l->t.t = BC_LEX_INVALID;
3247 s = BC_STATUS_LEX_BAD_CHAR;
3256 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3262 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3271 l->t.t = BC_LEX_OP_INC;
3274 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3280 l->t.t = BC_LEX_COMMA;
3289 l->t.t = BC_LEX_OP_DEC;
3292 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3298 if (isdigit(l->buf[l->i]))
3299 s = bc_lex_number(l, c);
3301 l->t.t = BC_LEX_KEY_LAST;
3302 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3311 s = bc_lex_comment(l);
3313 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3334 s = bc_lex_number(l, c);
3340 l->t.t = BC_LEX_SCOLON;
3346 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3352 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3358 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3365 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3371 if (l->buf[l->i] == '\n') {
3372 l->t.t = BC_LEX_WHITESPACE;
3376 s = BC_STATUS_LEX_BAD_CHAR;
3382 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3413 s = bc_lex_identifier(l);
3420 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3430 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3434 l->t.t = BC_LEX_OP_BOOL_OR;
3437 l->t.t = BC_LEX_INVALID;
3438 s = BC_STATUS_LEX_BAD_CHAR;
3446 l->t.t = BC_LEX_INVALID;
3447 s = BC_STATUS_LEX_BAD_CHAR;
3457 static BcStatus dc_lex_register(BcLex *l)
3459 BcStatus s = BC_STATUS_SUCCESS;
3461 if (isspace(l->buf[l->i - 1])) {
3462 bc_lex_whitespace(l);
3465 s = BC_STATUS_LEX_EXTENDED_REG;
3470 bc_vec_npop(&l->t.v, l->t.v.len);
3471 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3472 bc_vec_pushByte(&l->t.v, '\0');
3473 l->t.t = BC_LEX_NAME;
3479 static BcStatus dc_lex_string(BcLex *l)
3481 size_t depth = 1, nls = 0, i = l->i;
3484 l->t.t = BC_LEX_STR;
3485 bc_vec_npop(&l->t.v, l->t.v.len);
3487 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3489 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3490 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3493 if (depth) bc_vec_push(&l->t.v, &c);
3498 return BC_STATUS_LEX_NO_STRING_END;
3501 bc_vec_pushByte(&l->t.v, '\0');
3502 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3507 return BC_STATUS_SUCCESS;
3510 static BcStatus dc_lex_token(BcLex *l)
3512 BcStatus s = BC_STATUS_SUCCESS;
3513 char c = l->buf[l->i++], c2;
3516 for (i = 0; i < dc_lex_regs_len; ++i) {
3517 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3520 if (c >= '%' && c <= '~' &&
3521 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3526 // This is the workhorse of the lexer.
3531 l->t.t = BC_LEX_EOF;
3542 l->newline = (c == '\n');
3543 bc_lex_whitespace(l);
3552 l->t.t = BC_LEX_OP_REL_NE;
3554 l->t.t = BC_LEX_OP_REL_LE;
3556 l->t.t = BC_LEX_OP_REL_GE;
3558 return BC_STATUS_LEX_BAD_CHAR;
3566 bc_lex_lineComment(l);
3572 if (isdigit(l->buf[l->i]))
3573 s = bc_lex_number(l, c);
3575 s = BC_STATUS_LEX_BAD_CHAR;
3596 s = bc_lex_number(l, c);
3602 s = dc_lex_string(l);
3608 l->t.t = BC_LEX_INVALID;
3609 s = BC_STATUS_LEX_BAD_CHAR;
3618 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3620 bc_program_addFunc(p->prog, name, idx);
3621 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3624 static void bc_parse_pushName(BcParse *p, char *name)
3626 size_t i = 0, len = strlen(name);
3628 for (; i < len; ++i) bc_parse_push(p, name[i]);
3629 bc_parse_push(p, BC_PARSE_STREND);
3634 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3636 unsigned char amt, i, nums[sizeof(size_t)];
3638 for (amt = 0; idx; ++amt) {
3639 nums[amt] = (char) idx;
3640 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3643 bc_parse_push(p, amt);
3644 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3647 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3649 char *num = xstrdup(p->l.t.v.v);
3650 size_t idx = p->prog->consts.len;
3652 bc_vec_push(&p->prog->consts, &num);
3654 bc_parse_push(p, BC_INST_NUM);
3655 bc_parse_pushIndex(p, idx);
3658 (*prev) = BC_INST_NUM;
3661 static BcStatus bc_parse_text(BcParse *p, const char *text)
3665 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3667 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3668 p->l.t.t = BC_LEX_INVALID;
3671 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3674 return bc_lex_text(&p->l, text);
3677 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3679 if (p->fidx != BC_PROG_MAIN) {
3681 p->func->nparams = 0;
3682 bc_vec_npop(&p->func->code, p->func->code.len);
3683 bc_vec_npop(&p->func->autos, p->func->autos.len);
3684 bc_vec_npop(&p->func->labels, p->func->labels.len);
3686 bc_parse_updateFunc(p, BC_PROG_MAIN);
3690 p->l.t.t = BC_LEX_EOF;
3691 p->auto_part = (p->nbraces = 0);
3693 bc_vec_npop(&p->flags, p->flags.len - 1);
3694 bc_vec_npop(&p->exits, p->exits.len);
3695 bc_vec_npop(&p->conds, p->conds.len);
3696 bc_vec_npop(&p->ops, p->ops.len);
3698 return bc_program_reset(p->prog, s);
3701 static void bc_parse_free(BcParse *p)
3703 bc_vec_free(&p->flags);
3704 bc_vec_free(&p->exits);
3705 bc_vec_free(&p->conds);
3706 bc_vec_free(&p->ops);
3710 static void bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
3711 BcParseParse parse, BcLexNext next)
3713 memset(p, 0, sizeof(BcParse));
3715 bc_lex_init(&p->l, next);
3716 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3717 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3718 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3719 bc_vec_pushByte(&p->flags, 0);
3720 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3724 p->auto_part = (p->nbraces = 0);
3725 bc_parse_updateFunc(p, func);
3729 static BcStatus bc_parse_else(BcParse *p);
3730 static BcStatus bc_parse_stmt(BcParse *p);
3732 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3733 size_t *nexprs, bool next)
3735 BcStatus s = BC_STATUS_SUCCESS;
3737 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3738 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3740 while (p->ops.len > start) {
3742 t = BC_PARSE_TOP_OP(p);
3743 if (t == BC_LEX_LPAREN) break;
3745 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3746 if (l >= r && (l != r || !left)) break;
3748 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3749 bc_vec_pop(&p->ops);
3750 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3753 bc_vec_push(&p->ops, &type);
3754 if (next) s = bc_lex_next(&p->l);
3759 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3763 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3764 top = BC_PARSE_TOP_OP(p);
3766 while (top != BC_LEX_LPAREN) {
3768 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3770 bc_vec_pop(&p->ops);
3771 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3773 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3774 top = BC_PARSE_TOP_OP(p);
3777 bc_vec_pop(&p->ops);
3779 return bc_lex_next(&p->l);
3782 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3788 s = bc_lex_next(&p->l);
3791 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3793 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3794 s = bc_parse_expr(p, flags, bc_parse_next_param);
3797 comma = p->l.t.t == BC_LEX_COMMA;
3799 s = bc_lex_next(&p->l);
3804 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3805 bc_parse_push(p, BC_INST_CALL);
3806 bc_parse_pushIndex(p, nparams);
3808 return BC_STATUS_SUCCESS;
3811 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3814 BcId entry, *entry_ptr;
3819 s = bc_parse_params(p, flags);
3822 if (p->l.t.t != BC_LEX_RPAREN) {
3823 s = BC_STATUS_PARSE_BAD_TOKEN;
3827 idx = bc_map_index(&p->prog->fn_map, &entry);
3829 if (idx == BC_VEC_INVALID_IDX) {
3830 name = xstrdup(entry.name);
3831 bc_parse_addFunc(p, name, &idx);
3832 idx = bc_map_index(&p->prog->fn_map, &entry);
3838 entry_ptr = bc_vec_item(&p->prog->fn_map, idx);
3839 bc_parse_pushIndex(p, entry_ptr->idx);
3841 return bc_lex_next(&p->l);
3848 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3853 name = xstrdup(p->l.t.v.v);
3854 s = bc_lex_next(&p->l);
3857 if (p->l.t.t == BC_LEX_LBRACKET) {
3859 s = bc_lex_next(&p->l);
3862 if (p->l.t.t == BC_LEX_RBRACKET) {
3864 if (!(flags & BC_PARSE_ARRAY)) {
3865 s = BC_STATUS_PARSE_BAD_EXP;
3869 *type = BC_INST_ARRAY;
3873 *type = BC_INST_ARRAY_ELEM;
3875 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3876 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3880 s = bc_lex_next(&p->l);
3882 bc_parse_push(p, *type);
3883 bc_parse_pushName(p, name);
3885 else if (p->l.t.t == BC_LEX_LPAREN) {
3887 if (flags & BC_PARSE_NOCALL) {
3888 s = BC_STATUS_PARSE_BAD_TOKEN;
3892 *type = BC_INST_CALL;
3893 s = bc_parse_call(p, name, flags);
3896 *type = BC_INST_VAR;
3897 bc_parse_push(p, BC_INST_VAR);
3898 bc_parse_pushName(p, name);
3908 static BcStatus bc_parse_read(BcParse *p)
3912 s = bc_lex_next(&p->l);
3914 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3916 s = bc_lex_next(&p->l);
3918 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3920 bc_parse_push(p, BC_INST_READ);
3922 return bc_lex_next(&p->l);
3925 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3930 s = bc_lex_next(&p->l);
3932 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3934 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3936 s = bc_lex_next(&p->l);
3939 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3942 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3944 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3945 bc_parse_push(p, *prev);
3947 return bc_lex_next(&p->l);
3950 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3954 s = bc_lex_next(&p->l);
3957 if (p->l.t.t != BC_LEX_LPAREN) {
3958 *type = BC_INST_SCALE;
3959 bc_parse_push(p, BC_INST_SCALE);
3960 return BC_STATUS_SUCCESS;
3963 *type = BC_INST_SCALE_FUNC;
3964 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3966 s = bc_lex_next(&p->l);
3969 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3971 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3972 bc_parse_push(p, BC_INST_SCALE_FUNC);
3974 return bc_lex_next(&p->l);
3977 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3978 size_t *nexprs, uint8_t flags)
3983 BcInst etype = *prev;
3985 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3986 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3987 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3989 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3990 bc_parse_push(p, inst);
3991 s = bc_lex_next(&p->l);
3995 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3998 s = bc_lex_next(&p->l);
4002 // Because we parse the next part of the expression
4003 // right here, we need to increment this.
4004 *nexprs = *nexprs + 1;
4010 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4014 case BC_LEX_KEY_IBASE:
4015 case BC_LEX_KEY_LAST:
4016 case BC_LEX_KEY_OBASE:
4018 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4019 s = bc_lex_next(&p->l);
4023 case BC_LEX_KEY_SCALE:
4025 s = bc_lex_next(&p->l);
4027 if (p->l.t.t == BC_LEX_LPAREN)
4028 s = BC_STATUS_PARSE_BAD_TOKEN;
4030 bc_parse_push(p, BC_INST_SCALE);
4036 s = BC_STATUS_PARSE_BAD_TOKEN;
4041 if (!s) bc_parse_push(p, inst);
4047 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4048 bool rparen, size_t *nexprs)
4052 BcInst etype = *prev;
4054 s = bc_lex_next(&p->l);
4057 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4058 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4061 *prev = BC_PARSE_TOKEN_INST(type);
4063 // We can just push onto the op stack because this is the largest
4064 // precedence operator that gets pushed. Inc/dec does not.
4065 if (type != BC_LEX_OP_MINUS)
4066 bc_vec_push(&p->ops, &type);
4068 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4073 static BcStatus bc_parse_string(BcParse *p, char inst)
4075 char *str = xstrdup(p->l.t.v.v);
4077 bc_parse_push(p, BC_INST_STR);
4078 bc_parse_pushIndex(p, p->prog->strs.len);
4079 bc_vec_push(&p->prog->strs, &str);
4080 bc_parse_push(p, inst);
4082 return bc_lex_next(&p->l);
4085 static BcStatus bc_parse_print(BcParse *p)
4091 s = bc_lex_next(&p->l);
4096 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4097 return BC_STATUS_PARSE_BAD_PRINT;
4099 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4101 if (type == BC_LEX_STR)
4102 s = bc_parse_string(p, BC_INST_PRINT_POP);
4104 s = bc_parse_expr(p, 0, bc_parse_next_print);
4106 bc_parse_push(p, BC_INST_PRINT_POP);
4111 comma = p->l.t.t == BC_LEX_COMMA;
4112 if (comma) s = bc_lex_next(&p->l);
4117 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4119 return bc_lex_next(&p->l);
4122 static BcStatus bc_parse_return(BcParse *p)
4128 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4130 s = bc_lex_next(&p->l);
4134 paren = t == BC_LEX_LPAREN;
4136 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4137 bc_parse_push(p, BC_INST_RET0);
4140 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4141 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4143 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4144 bc_parse_push(p, BC_INST_RET0);
4145 s = bc_lex_next(&p->l);
4149 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4150 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4154 bc_parse_push(p, BC_INST_RET);
4160 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4162 BcStatus s = BC_STATUS_SUCCESS;
4164 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4165 return BC_STATUS_PARSE_BAD_TOKEN;
4169 if (p->l.t.t == BC_LEX_RBRACE) {
4170 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4172 s = bc_lex_next(&p->l);
4176 return BC_STATUS_PARSE_BAD_TOKEN;
4179 if (BC_PARSE_IF(p)) {
4183 while (p->l.t.t == BC_LEX_NLINE) {
4184 s = bc_lex_next(&p->l);
4188 bc_vec_pop(&p->flags);
4190 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4191 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4193 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4195 else if (BC_PARSE_ELSE(p)) {
4200 bc_vec_pop(&p->flags);
4202 ip = bc_vec_top(&p->exits);
4203 label = bc_vec_item(&p->func->labels, ip->idx);
4204 *label = p->func->code.len;
4206 bc_vec_pop(&p->exits);
4208 else if (BC_PARSE_FUNC_INNER(p)) {
4209 bc_parse_push(p, BC_INST_RET0);
4210 bc_parse_updateFunc(p, BC_PROG_MAIN);
4211 bc_vec_pop(&p->flags);
4215 BcInstPtr *ip = bc_vec_top(&p->exits);
4216 size_t *label = bc_vec_top(&p->conds);
4218 bc_parse_push(p, BC_INST_JUMP);
4219 bc_parse_pushIndex(p, *label);
4221 label = bc_vec_item(&p->func->labels, ip->idx);
4222 *label = p->func->code.len;
4224 bc_vec_pop(&p->flags);
4225 bc_vec_pop(&p->exits);
4226 bc_vec_pop(&p->conds);
4232 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4234 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4235 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4236 flags |= BC_PARSE_FLAG_BODY;
4237 bc_vec_push(&p->flags, &flags);
4240 static void bc_parse_noElse(BcParse *p)
4244 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4246 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4248 ip = bc_vec_top(&p->exits);
4249 label = bc_vec_item(&p->func->labels, ip->idx);
4250 *label = p->func->code.len;
4252 bc_vec_pop(&p->exits);
4255 static BcStatus bc_parse_if(BcParse *p)
4260 s = bc_lex_next(&p->l);
4262 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4264 s = bc_lex_next(&p->l);
4266 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4268 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4270 s = bc_lex_next(&p->l);
4272 bc_parse_push(p, BC_INST_JUMP_ZERO);
4274 ip.idx = p->func->labels.len;
4275 ip.func = ip.len = 0;
4277 bc_parse_pushIndex(p, ip.idx);
4278 bc_vec_push(&p->exits, &ip);
4279 bc_vec_push(&p->func->labels, &ip.idx);
4280 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4282 return BC_STATUS_SUCCESS;
4285 static BcStatus bc_parse_else(BcParse *p)
4289 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4291 ip.idx = p->func->labels.len;
4292 ip.func = ip.len = 0;
4294 bc_parse_push(p, BC_INST_JUMP);
4295 bc_parse_pushIndex(p, ip.idx);
4299 bc_vec_push(&p->exits, &ip);
4300 bc_vec_push(&p->func->labels, &ip.idx);
4301 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4303 return bc_lex_next(&p->l);
4306 static BcStatus bc_parse_while(BcParse *p)
4311 s = bc_lex_next(&p->l);
4313 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4314 s = bc_lex_next(&p->l);
4317 ip.idx = p->func->labels.len;
4319 bc_vec_push(&p->func->labels, &p->func->code.len);
4320 bc_vec_push(&p->conds, &ip.idx);
4322 ip.idx = p->func->labels.len;
4326 bc_vec_push(&p->exits, &ip);
4327 bc_vec_push(&p->func->labels, &ip.idx);
4329 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4331 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4332 s = bc_lex_next(&p->l);
4335 bc_parse_push(p, BC_INST_JUMP_ZERO);
4336 bc_parse_pushIndex(p, ip.idx);
4337 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4339 return BC_STATUS_SUCCESS;
4342 static BcStatus bc_parse_for(BcParse *p)
4346 size_t cond_idx, exit_idx, body_idx, update_idx;
4348 s = bc_lex_next(&p->l);
4350 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4351 s = bc_lex_next(&p->l);
4354 if (p->l.t.t != BC_LEX_SCOLON)
4355 s = bc_parse_expr(p, 0, bc_parse_next_for);
4357 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4360 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4361 s = bc_lex_next(&p->l);
4364 cond_idx = p->func->labels.len;
4365 update_idx = cond_idx + 1;
4366 body_idx = update_idx + 1;
4367 exit_idx = body_idx + 1;
4369 bc_vec_push(&p->func->labels, &p->func->code.len);
4371 if (p->l.t.t != BC_LEX_SCOLON)
4372 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4374 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4377 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4379 s = bc_lex_next(&p->l);
4382 bc_parse_push(p, BC_INST_JUMP_ZERO);
4383 bc_parse_pushIndex(p, exit_idx);
4384 bc_parse_push(p, BC_INST_JUMP);
4385 bc_parse_pushIndex(p, body_idx);
4387 ip.idx = p->func->labels.len;
4389 bc_vec_push(&p->conds, &update_idx);
4390 bc_vec_push(&p->func->labels, &p->func->code.len);
4392 if (p->l.t.t != BC_LEX_RPAREN)
4393 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4395 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4399 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4400 bc_parse_push(p, BC_INST_JUMP);
4401 bc_parse_pushIndex(p, cond_idx);
4402 bc_vec_push(&p->func->labels, &p->func->code.len);
4408 bc_vec_push(&p->exits, &ip);
4409 bc_vec_push(&p->func->labels, &ip.idx);
4411 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4413 return BC_STATUS_SUCCESS;
4416 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4422 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4424 if (type == BC_LEX_KEY_BREAK) {
4426 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4428 i = p->exits.len - 1;
4429 ip = bc_vec_item(&p->exits, i);
4431 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4432 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4437 i = *((size_t *) bc_vec_top(&p->conds));
4439 bc_parse_push(p, BC_INST_JUMP);
4440 bc_parse_pushIndex(p, i);
4442 s = bc_lex_next(&p->l);
4445 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4446 return BC_STATUS_PARSE_BAD_TOKEN;
4448 return bc_lex_next(&p->l);
4451 static BcStatus bc_parse_func(BcParse *p)
4454 bool var, comma = false;
4458 s = bc_lex_next(&p->l);
4460 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4462 name = xstrdup(p->l.t.v.v);
4463 bc_parse_addFunc(p, name, &p->fidx);
4465 s = bc_lex_next(&p->l);
4467 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4468 s = bc_lex_next(&p->l);
4471 while (p->l.t.t != BC_LEX_RPAREN) {
4473 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4477 name = xstrdup(p->l.t.v.v);
4478 s = bc_lex_next(&p->l);
4481 var = p->l.t.t != BC_LEX_LBRACKET;
4485 s = bc_lex_next(&p->l);
4488 if (p->l.t.t != BC_LEX_RBRACKET) {
4489 s = BC_STATUS_PARSE_BAD_FUNC;
4493 s = bc_lex_next(&p->l);
4497 comma = p->l.t.t == BC_LEX_COMMA;
4499 s = bc_lex_next(&p->l);
4503 s = bc_func_insert(p->func, name, var);
4507 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4509 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4510 bc_parse_startBody(p, flags);
4512 s = bc_lex_next(&p->l);
4515 if (p->l.t.t != BC_LEX_LBRACE)
4516 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4525 static BcStatus bc_parse_auto(BcParse *p)
4528 bool comma, var, one;
4531 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4532 s = bc_lex_next(&p->l);
4535 p->auto_part = comma = false;
4536 one = p->l.t.t == BC_LEX_NAME;
4538 while (p->l.t.t == BC_LEX_NAME) {
4540 name = xstrdup(p->l.t.v.v);
4541 s = bc_lex_next(&p->l);
4544 var = p->l.t.t != BC_LEX_LBRACKET;
4547 s = bc_lex_next(&p->l);
4550 if (p->l.t.t != BC_LEX_RBRACKET) {
4551 s = BC_STATUS_PARSE_BAD_FUNC;
4555 s = bc_lex_next(&p->l);
4559 comma = p->l.t.t == BC_LEX_COMMA;
4561 s = bc_lex_next(&p->l);
4565 s = bc_func_insert(p->func, name, var);
4569 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4570 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4572 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4573 return BC_STATUS_PARSE_BAD_TOKEN;
4575 return bc_lex_next(&p->l);
4582 static BcStatus bc_parse_body(BcParse *p, bool brace)
4584 BcStatus s = BC_STATUS_SUCCESS;
4585 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4587 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4589 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4591 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4592 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4594 if (!p->auto_part) {
4595 s = bc_parse_auto(p);
4599 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4602 s = bc_parse_stmt(p);
4603 if (!s && !brace) s = bc_parse_endBody(p, false);
4609 static BcStatus bc_parse_stmt(BcParse *p)
4611 BcStatus s = BC_STATUS_SUCCESS;
4617 return bc_lex_next(&p->l);
4620 case BC_LEX_KEY_ELSE:
4622 p->auto_part = false;
4628 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4631 s = bc_lex_next(&p->l);
4634 return bc_parse_body(p, true);
4637 case BC_LEX_KEY_AUTO:
4639 return bc_parse_auto(p);
4644 p->auto_part = false;
4646 if (BC_PARSE_IF_END(p)) {
4648 return BC_STATUS_SUCCESS;
4650 else if (BC_PARSE_BODY(p))
4651 return bc_parse_body(p, false);
4661 case BC_LEX_OP_MINUS:
4662 case BC_LEX_OP_BOOL_NOT:
4666 case BC_LEX_KEY_IBASE:
4667 case BC_LEX_KEY_LAST:
4668 case BC_LEX_KEY_LENGTH:
4669 case BC_LEX_KEY_OBASE:
4670 case BC_LEX_KEY_READ:
4671 case BC_LEX_KEY_SCALE:
4672 case BC_LEX_KEY_SQRT:
4674 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4678 case BC_LEX_KEY_ELSE:
4680 s = bc_parse_else(p);
4686 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4692 s = bc_parse_endBody(p, true);
4698 s = bc_parse_string(p, BC_INST_PRINT_STR);
4702 case BC_LEX_KEY_BREAK:
4703 case BC_LEX_KEY_CONTINUE:
4705 s = bc_parse_loopExit(p, p->l.t.t);
4709 case BC_LEX_KEY_FOR:
4711 s = bc_parse_for(p);
4715 case BC_LEX_KEY_HALT:
4717 bc_parse_push(p, BC_INST_HALT);
4718 s = bc_lex_next(&p->l);
4728 case BC_LEX_KEY_LIMITS:
4730 s = bc_lex_next(&p->l);
4732 s = BC_STATUS_LIMITS;
4736 case BC_LEX_KEY_PRINT:
4738 s = bc_parse_print(p);
4742 case BC_LEX_KEY_QUIT:
4744 // Quit is a compile-time command. We don't exit directly,
4745 // so the vm can clean up. Limits do the same thing.
4750 case BC_LEX_KEY_RETURN:
4752 s = bc_parse_return(p);
4756 case BC_LEX_KEY_WHILE:
4758 s = bc_parse_while(p);
4764 s = BC_STATUS_PARSE_BAD_TOKEN;
4772 static BcStatus bc_parse_parse(BcParse *p)
4776 if (p->l.t.t == BC_LEX_EOF)
4777 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4778 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4779 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4780 s = bc_parse_func(p);
4783 s = bc_parse_stmt(p);
4785 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || bcg.signe)
4786 s = bc_parse_reset(p, s);
4791 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4793 BcStatus s = BC_STATUS_SUCCESS;
4794 BcInst prev = BC_INST_PRINT;
4795 BcLexType top, t = p->l.t.t;
4796 size_t nexprs = 0, ops_bgn = p->ops.len;
4797 uint32_t i, nparens, nrelops;
4798 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4800 paren_first = p->l.t.t == BC_LEX_LPAREN;
4801 nparens = nrelops = 0;
4802 paren_expr = rprn = done = get_token = assign = false;
4805 for (; !bcg.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4811 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4812 rprn = get_token = bin_last = false;
4816 case BC_LEX_OP_MINUS:
4818 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4819 rprn = get_token = false;
4820 bin_last = prev == BC_INST_MINUS;
4824 case BC_LEX_OP_ASSIGN_POWER:
4825 case BC_LEX_OP_ASSIGN_MULTIPLY:
4826 case BC_LEX_OP_ASSIGN_DIVIDE:
4827 case BC_LEX_OP_ASSIGN_MODULUS:
4828 case BC_LEX_OP_ASSIGN_PLUS:
4829 case BC_LEX_OP_ASSIGN_MINUS:
4830 case BC_LEX_OP_ASSIGN:
4832 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4833 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4834 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4836 s = BC_STATUS_PARSE_BAD_ASSIGN;
4841 case BC_LEX_OP_POWER:
4842 case BC_LEX_OP_MULTIPLY:
4843 case BC_LEX_OP_DIVIDE:
4844 case BC_LEX_OP_MODULUS:
4845 case BC_LEX_OP_PLUS:
4846 case BC_LEX_OP_REL_EQ:
4847 case BC_LEX_OP_REL_LE:
4848 case BC_LEX_OP_REL_GE:
4849 case BC_LEX_OP_REL_NE:
4850 case BC_LEX_OP_REL_LT:
4851 case BC_LEX_OP_REL_GT:
4852 case BC_LEX_OP_BOOL_NOT:
4853 case BC_LEX_OP_BOOL_OR:
4854 case BC_LEX_OP_BOOL_AND:
4856 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4857 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4859 return BC_STATUS_PARSE_BAD_EXP;
4862 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4863 prev = BC_PARSE_TOKEN_INST(t);
4864 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4865 rprn = get_token = false;
4866 bin_last = t != BC_LEX_OP_BOOL_NOT;
4873 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4876 paren_expr = rprn = bin_last = false;
4878 bc_vec_push(&p->ops, &t);
4885 if (bin_last || prev == BC_INST_BOOL_NOT)
4886 return BC_STATUS_PARSE_BAD_EXP;
4889 s = BC_STATUS_SUCCESS;
4894 else if (!paren_expr)
4895 return BC_STATUS_PARSE_EMPTY_EXP;
4898 paren_expr = rprn = true;
4899 get_token = bin_last = false;
4901 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4908 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4911 rprn = get_token = bin_last = false;
4912 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4920 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4922 bc_parse_number(p, &prev, &nexprs);
4923 paren_expr = get_token = true;
4924 rprn = bin_last = false;
4929 case BC_LEX_KEY_IBASE:
4930 case BC_LEX_KEY_LAST:
4931 case BC_LEX_KEY_OBASE:
4933 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4935 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4936 bc_parse_push(p, (char) prev);
4938 paren_expr = get_token = true;
4939 rprn = bin_last = false;
4945 case BC_LEX_KEY_LENGTH:
4946 case BC_LEX_KEY_SQRT:
4948 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4950 s = bc_parse_builtin(p, t, flags, &prev);
4952 rprn = get_token = bin_last = false;
4958 case BC_LEX_KEY_READ:
4960 if (BC_PARSE_LEAF(prev, rprn))
4961 return BC_STATUS_PARSE_BAD_EXP;
4962 else if (flags & BC_PARSE_NOREAD)
4963 s = BC_STATUS_EXEC_REC_READ;
4965 s = bc_parse_read(p);
4968 rprn = get_token = bin_last = false;
4970 prev = BC_INST_READ;
4975 case BC_LEX_KEY_SCALE:
4977 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4979 s = bc_parse_scale(p, &prev, flags);
4981 rprn = get_token = bin_last = false;
4983 prev = BC_INST_SCALE;
4990 s = BC_STATUS_PARSE_BAD_TOKEN;
4995 if (!s && get_token) s = bc_lex_next(&p->l);
4999 if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
5001 while (p->ops.len > ops_bgn) {
5003 top = BC_PARSE_TOP_OP(p);
5004 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
5006 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
5007 return BC_STATUS_PARSE_BAD_EXP;
5009 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5011 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5012 bc_vec_pop(&p->ops);
5015 s = BC_STATUS_PARSE_BAD_EXP;
5016 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5018 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5021 if (!(flags & BC_PARSE_REL) && nrelops) {
5022 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5025 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5026 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5030 if (flags & BC_PARSE_PRINT) {
5031 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5032 bc_parse_push(p, BC_INST_POP);
5038 static void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5040 bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
5043 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5045 return bc_parse_expr(p, flags, bc_parse_next_read);
5050 static BcStatus dc_parse_register(BcParse *p)
5055 s = bc_lex_next(&p->l);
5057 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5059 name = xstrdup(p->l.t.v.v);
5060 bc_parse_pushName(p, name);
5065 static BcStatus dc_parse_string(BcParse *p)
5067 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5068 size_t idx, len = p->prog->strs.len;
5070 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5073 str = xstrdup(p->l.t.v.v);
5074 bc_parse_push(p, BC_INST_STR);
5075 bc_parse_pushIndex(p, len);
5076 bc_vec_push(&p->prog->strs, &str);
5077 bc_parse_addFunc(p, name, &idx);
5079 return bc_lex_next(&p->l);
5082 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5086 bc_parse_push(p, inst);
5088 s = dc_parse_register(p);
5093 bc_parse_push(p, BC_INST_SWAP);
5094 bc_parse_push(p, BC_INST_ASSIGN);
5095 bc_parse_push(p, BC_INST_POP);
5098 return bc_lex_next(&p->l);
5101 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5105 bc_parse_push(p, inst);
5106 bc_parse_push(p, BC_INST_EXEC_COND);
5108 s = dc_parse_register(p);
5111 s = bc_lex_next(&p->l);
5114 if (p->l.t.t == BC_LEX_ELSE) {
5115 s = dc_parse_register(p);
5117 s = bc_lex_next(&p->l);
5120 bc_parse_push(p, BC_PARSE_STREND);
5125 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5127 BcStatus s = BC_STATUS_SUCCESS;
5130 bool assign, get_token = false;
5134 case BC_LEX_OP_REL_EQ:
5135 case BC_LEX_OP_REL_LE:
5136 case BC_LEX_OP_REL_GE:
5137 case BC_LEX_OP_REL_NE:
5138 case BC_LEX_OP_REL_LT:
5139 case BC_LEX_OP_REL_GT:
5141 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5148 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5154 s = dc_parse_string(p);
5161 if (t == BC_LEX_NEG) {
5162 s = bc_lex_next(&p->l);
5164 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5167 bc_parse_number(p, &prev, &p->nbraces);
5169 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5175 case BC_LEX_KEY_READ:
5177 if (flags & BC_PARSE_NOREAD)
5178 s = BC_STATUS_EXEC_REC_READ;
5180 bc_parse_push(p, BC_INST_READ);
5185 case BC_LEX_OP_ASSIGN:
5186 case BC_LEX_STORE_PUSH:
5188 assign = t == BC_LEX_OP_ASSIGN;
5189 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5190 s = dc_parse_mem(p, inst, true, assign);
5195 case BC_LEX_LOAD_POP:
5197 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5198 s = dc_parse_mem(p, inst, true, false);
5202 case BC_LEX_STORE_IBASE:
5203 case BC_LEX_STORE_SCALE:
5204 case BC_LEX_STORE_OBASE:
5206 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5207 s = dc_parse_mem(p, inst, false, true);
5213 s = BC_STATUS_PARSE_BAD_TOKEN;
5219 if (!s && get_token) s = bc_lex_next(&p->l);
5224 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5226 BcStatus s = BC_STATUS_SUCCESS;
5230 if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
5232 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5234 inst = dc_parse_insts[t];
5236 if (inst != BC_INST_INVALID) {
5237 bc_parse_push(p, inst);
5238 s = bc_lex_next(&p->l);
5241 s = dc_parse_token(p, t, flags);
5244 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5245 bc_parse_push(p, BC_INST_POP_EXEC);
5250 static BcStatus dc_parse_parse(BcParse *p)
5254 if (p->l.t.t == BC_LEX_EOF)
5255 s = BC_STATUS_LEX_EOF;
5257 s = dc_parse_expr(p, 0);
5259 if (s || bcg.signe) s = bc_parse_reset(p, s);
5264 static void dc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5266 bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
5270 static void bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
5279 v = var ? &p->vars : &p->arrs;
5280 map = var ? &p->var_map : &p->arr_map;
5284 s = bc_map_insert(map, &e, &i);
5285 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5288 bc_array_init(&data.v, var);
5289 bc_vec_push(v, &data.v);
5292 ptr = bc_vec_item(map, i);
5293 if (new) ptr->name = xstrdup(e.name);
5294 *ret = bc_vec_item(v, ptr->idx);
5297 static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
5299 BcStatus s = BC_STATUS_SUCCESS;
5304 case BC_RESULT_TEMP:
5305 case BC_RESULT_IBASE:
5306 case BC_RESULT_SCALE:
5307 case BC_RESULT_OBASE:
5313 case BC_RESULT_CONSTANT:
5315 char **str = bc_vec_item(&p->consts, r->d.id.idx);
5316 size_t base_t, len = strlen(*str);
5319 bc_num_init(&r->d.n, len);
5321 hex = hex && len == 1;
5322 base = hex ? &p->hexb : &p->ib;
5323 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
5324 s = bc_num_parse(&r->d.n, *str, base, base_t);
5327 bc_num_free(&r->d.n);
5332 r->t = BC_RESULT_TEMP;
5338 case BC_RESULT_ARRAY:
5339 case BC_RESULT_ARRAY_ELEM:
5343 bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
5345 if (r->t == BC_RESULT_ARRAY_ELEM) {
5347 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5348 *num = bc_vec_item(v, r->d.id.idx);
5351 *num = bc_vec_top(v);
5356 case BC_RESULT_LAST:
5372 static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
5373 BcResult **r, BcNum **rn, bool assign)
5377 BcResultType lt, rt;
5379 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5381 *r = bc_vec_item_rev(&p->results, 0);
5382 *l = bc_vec_item_rev(&p->results, 1);
5386 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5388 s = bc_program_num(p, *l, ln, false);
5390 s = bc_program_num(p, *r, rn, hex);
5393 // We run this again under these conditions in case any vector has been
5394 // reallocated out from under the BcNums or arrays we had.
5395 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5396 s = bc_program_num(p, *l, ln, false);
5400 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5401 return BC_STATUS_EXEC_BAD_TYPE;
5402 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5407 static void bc_program_binOpRetire(BcProgram *p, BcResult *r)
5409 r->t = BC_RESULT_TEMP;
5410 bc_vec_pop(&p->results);
5411 bc_vec_pop(&p->results);
5412 bc_vec_push(&p->results, r);
5415 static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n)
5419 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5420 *r = bc_vec_top(&p->results);
5422 s = bc_program_num(p, *r, n, false);
5425 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5430 static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t)
5433 bc_vec_pop(&p->results);
5434 bc_vec_push(&p->results, r);
5437 static BcStatus bc_program_op(BcProgram *p, char inst)
5440 BcResult *opd1, *opd2, res;
5441 BcNum *n1, *n2 = NULL;
5443 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5445 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5447 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale);
5449 bc_program_binOpRetire(p, &res);
5454 bc_num_free(&res.d.n);
5458 static BcStatus bc_program_read(BcProgram *p)
5465 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
5467 for (i = 0; i < p->stack.len; ++i) {
5468 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
5469 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5472 bc_vec_npop(&f->code, f->code.len);
5473 bc_vec_init(&buf, sizeof(char), NULL);
5475 s = bc_read_line(&buf, "read> ");
5478 p->parse_init(&parse, p, BC_PROG_READ);
5479 bc_lex_file(&parse.l, bc_program_stdin_name);
5481 s = bc_parse_text(&parse, buf.v);
5482 if (s) goto exec_err;
5483 s = p->parse_expr(&parse, BC_PARSE_NOREAD);
5484 if (s) goto exec_err;
5486 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5487 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5491 ip.func = BC_PROG_READ;
5493 ip.len = p->results.len;
5495 // Update this pointer, just in case.
5496 f = bc_vec_item(&p->fns, BC_PROG_READ);
5498 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5499 bc_vec_push(&p->stack, &ip);
5502 bc_parse_free(&parse);
5508 static size_t bc_program_index(char *code, size_t *bgn)
5510 char amt = code[(*bgn)++], i = 0;
5513 for (; i < amt; ++i, ++(*bgn))
5514 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5519 static char *bc_program_name(char *code, size_t *bgn)
5522 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5524 s = xmalloc(ptr - str + 1);
5527 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5535 static void bc_program_printString(const char *str, size_t *nchars)
5537 size_t i, len = strlen(str);
5546 for (i = 0; i < len; ++i, ++(*nchars)) {
5550 if (c != '\\' || i == len - 1)
5610 // Just print the backslash and following character.
5621 static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
5623 BcStatus s = BC_STATUS_SUCCESS;
5628 bool pop = inst != BC_INST_PRINT;
5630 if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
5632 r = bc_vec_item_rev(&p->results, idx);
5633 s = bc_program_num(p, r, &num, false);
5636 if (BC_PROG_NUM(r, num)) {
5637 s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
5638 if (!s) bc_num_copy(&p->last, num);
5642 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5643 str = *((char **) bc_vec_item(&p->strs, idx));
5645 if (inst == BC_INST_PRINT_STR) {
5646 for (i = 0, len = strlen(str); i < len; ++i) {
5649 if (c == '\n') p->nchars = SIZE_MAX;
5654 bc_program_printString(str, &p->nchars);
5655 if (inst == BC_INST_PRINT) bb_putchar('\n');
5659 if (!s && pop) bc_vec_pop(&p->results);
5664 static BcStatus bc_program_negate(BcProgram *p)
5670 s = bc_program_prep(p, &ptr, &num);
5673 bc_num_init(&res.d.n, num->len);
5674 bc_num_copy(&res.d.n, num);
5675 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5677 bc_program_retire(p, &res, BC_RESULT_TEMP);
5682 static BcStatus bc_program_logical(BcProgram *p, char inst)
5685 BcResult *opd1, *opd2, res;
5690 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5692 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5694 if (inst == BC_INST_BOOL_AND)
5695 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
5696 else if (inst == BC_INST_BOOL_OR)
5697 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
5700 cmp = bc_num_cmp(n1, n2);
5704 case BC_INST_REL_EQ:
5710 case BC_INST_REL_LE:
5716 case BC_INST_REL_GE:
5722 case BC_INST_REL_NE:
5728 case BC_INST_REL_LT:
5734 case BC_INST_REL_GT:
5742 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5744 bc_program_binOpRetire(p, &res);
5750 static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
5756 memset(&n2, 0, sizeof(BcNum));
5757 n2.rdx = res.d.id.idx = r->d.id.idx;
5758 res.t = BC_RESULT_STR;
5761 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5763 bc_vec_pop(&p->results);
5766 bc_vec_pop(&p->results);
5768 bc_vec_push(&p->results, &res);
5769 bc_vec_push(v, &n2);
5771 return BC_STATUS_SUCCESS;
5775 static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var)
5782 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5784 ptr = bc_vec_top(&p->results);
5785 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5786 bc_program_search(p, name, &v, var);
5789 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5790 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
5793 s = bc_program_num(p, ptr, &n, false);
5796 // Do this once more to make sure that pointers were not invalidated.
5797 bc_program_search(p, name, &v, var);
5800 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5801 bc_num_copy(&r.d.n, n);
5804 bc_array_init(&r.d.v, true);
5805 bc_array_copy(&r.d.v, (BcVec *) n);
5808 bc_vec_push(v, &r.d);
5809 bc_vec_pop(&p->results);
5814 static BcStatus bc_program_assign(BcProgram *p, char inst)
5817 BcResult *left, *right, res;
5818 BcNum *l = NULL, *r = NULL;
5819 unsigned long val, max;
5820 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5822 s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign);
5825 ib = left->t == BC_RESULT_IBASE;
5826 sc = left->t == BC_RESULT_SCALE;
5830 if (right->t == BC_RESULT_STR) {
5834 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5835 bc_program_search(p, left->d.id.name, &v, true);
5837 return bc_program_assignStr(p, right, v, false);
5841 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5842 return BC_STATUS_PARSE_BAD_ASSIGN;
5845 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
5846 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5851 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5858 if (ib || sc || left->t == BC_RESULT_OBASE) {
5862 s = bc_num_ulong(l, &val);
5864 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5871 if (val < BC_NUM_MIN_BASE) return s;
5872 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5873 ptr = ib ? &p->ib_t : &p->ob_t;
5876 if (val > max) return s;
5877 if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l);
5879 *ptr = (size_t) val;
5880 s = BC_STATUS_SUCCESS;
5883 bc_num_init(&res.d.n, l->len);
5884 bc_num_copy(&res.d.n, l);
5885 bc_program_binOpRetire(p, &res);
5890 static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
5891 bool pop, bool copy)
5893 BcStatus s = BC_STATUS_SUCCESS;
5895 char *name = bc_program_name(code, bgn);
5896 #if ENABLE_DC // Exclude
5900 (void) pop, (void) copy;
5903 r.t = BC_RESULT_VAR;
5907 bc_program_search(p, name, &v, true);
5908 num = bc_vec_top(v);
5912 if (!BC_PROG_STACK(v, 2 - copy)) {
5914 return BC_STATUS_EXEC_STACK;
5920 if (!BC_PROG_STR(num)) {
5922 r.t = BC_RESULT_TEMP;
5924 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5925 bc_num_copy(&r.d.n, num);
5928 r.t = BC_RESULT_STR;
5929 r.d.id.idx = num->rdx;
5932 if (!copy) bc_vec_pop(v);
5936 bc_vec_push(&p->results, &r);
5941 static BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn,
5944 BcStatus s = BC_STATUS_SUCCESS;
5948 r.d.id.name = bc_program_name(code, bgn);
5950 if (inst == BC_INST_ARRAY) {
5951 r.t = BC_RESULT_ARRAY;
5952 bc_vec_push(&p->results, &r);
5959 s = bc_program_prep(p, &operand, &num);
5961 s = bc_num_ulong(num, &temp);
5964 if (temp > BC_MAX_DIM) {
5965 s = BC_STATUS_EXEC_ARRAY_LEN;
5969 r.d.id.idx = (size_t) temp;
5970 bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
5974 if (s) free(r.d.id.name);
5979 static BcStatus bc_program_incdec(BcProgram *p, char inst)
5982 BcResult *ptr, res, copy;
5986 s = bc_program_prep(p, &ptr, &num);
5989 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5990 copy.t = BC_RESULT_TEMP;
5991 bc_num_init(©.d.n, num->len);
5992 bc_num_copy(©.d.n, num);
5995 res.t = BC_RESULT_ONE;
5996 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5997 BC_INST_ASSIGN_PLUS :
5998 BC_INST_ASSIGN_MINUS;
6000 bc_vec_push(&p->results, &res);
6001 bc_program_assign(p, inst);
6003 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
6004 bc_vec_pop(&p->results);
6005 bc_vec_push(&p->results, ©);
6011 static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx)
6013 BcStatus s = BC_STATUS_SUCCESS;
6015 size_t i, nparams = bc_program_index(code, idx);
6023 ip.func = bc_program_index(code, idx);
6024 func = bc_vec_item(&p->fns, ip.func);
6026 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6027 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6028 ip.len = p->results.len - nparams;
6030 for (i = 0; i < nparams; ++i) {
6032 a = bc_vec_item(&func->autos, nparams - 1 - i);
6033 arg = bc_vec_top(&p->results);
6035 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6036 return BC_STATUS_EXEC_BAD_TYPE;
6038 s = bc_program_copyToVar(p, a->name, a->idx);
6042 for (; i < func->autos.len; ++i) {
6044 a = bc_vec_item(&func->autos, i);
6045 bc_program_search(p, a->name, &v, a->idx);
6048 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6049 bc_vec_push(v, ¶m.n);
6052 bc_array_init(¶m.v, true);
6053 bc_vec_push(v, ¶m.v);
6057 bc_vec_push(&p->stack, &ip);
6059 return BC_STATUS_SUCCESS;
6062 static BcStatus bc_program_return(BcProgram *p, char inst)
6068 BcInstPtr *ip = bc_vec_top(&p->stack);
6070 if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
6071 return BC_STATUS_EXEC_STACK;
6073 f = bc_vec_item(&p->fns, ip->func);
6074 res.t = BC_RESULT_TEMP;
6076 if (inst == BC_INST_RET) {
6079 BcResult *operand = bc_vec_top(&p->results);
6081 s = bc_program_num(p, operand, &num, false);
6083 bc_num_init(&res.d.n, num->len);
6084 bc_num_copy(&res.d.n, num);
6087 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6088 bc_num_zero(&res.d.n);
6091 // We need to pop arguments as well, so this takes that into account.
6092 for (i = 0; i < f->autos.len; ++i) {
6095 BcId *a = bc_vec_item(&f->autos, i);
6097 bc_program_search(p, a->name, &v, a->idx);
6101 bc_vec_npop(&p->results, p->results.len - ip->len);
6102 bc_vec_push(&p->results, &res);
6103 bc_vec_pop(&p->stack);
6105 return BC_STATUS_SUCCESS;
6109 static unsigned long bc_program_scale(BcNum *n)
6111 return (unsigned long) n->rdx;
6114 static unsigned long bc_program_len(BcNum *n)
6116 unsigned long len = n->len;
6119 if (n->rdx != n->len) return len;
6120 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6125 static BcStatus bc_program_builtin(BcProgram *p, char inst)
6131 bool len = inst == BC_INST_LENGTH;
6133 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6134 opnd = bc_vec_top(&p->results);
6136 s = bc_program_num(p, opnd, &num, false);
6140 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6143 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6145 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
6147 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6148 s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6152 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6155 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6157 str = bc_vec_item(&p->strs, idx);
6158 s = bc_num_ulong2num(&res.d.n, strlen(*str));
6163 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6164 s = bc_num_ulong2num(&res.d.n, f(num));
6168 bc_program_retire(p, &res, BC_RESULT_TEMP);
6173 bc_num_free(&res.d.n);
6178 static BcStatus bc_program_divmod(BcProgram *p)
6181 BcResult *opd1, *opd2, res, res2;
6182 BcNum *n1, *n2 = NULL;
6184 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
6187 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6188 bc_num_init(&res2.d.n, n2->len);
6190 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale);
6193 bc_program_binOpRetire(p, &res2);
6194 res.t = BC_RESULT_TEMP;
6195 bc_vec_push(&p->results, &res);
6200 bc_num_free(&res2.d.n);
6201 bc_num_free(&res.d.n);
6205 static BcStatus bc_program_modexp(BcProgram *p)
6208 BcResult *r1, *r2, *r3, res;
6209 BcNum *n1, *n2, *n3;
6211 if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
6212 s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false);
6215 r1 = bc_vec_item_rev(&p->results, 2);
6216 s = bc_program_num(p, r1, &n1, false);
6218 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6220 // Make sure that the values have their pointers updated, if necessary.
6221 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6223 if (r1->t == r2->t) {
6224 s = bc_program_num(p, r2, &n2, false);
6228 if (r1->t == r3->t) {
6229 s = bc_program_num(p, r3, &n3, false);
6234 bc_num_init(&res.d.n, n3->len);
6235 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6238 bc_vec_pop(&p->results);
6239 bc_program_binOpRetire(p, &res);
6244 bc_num_free(&res.d.n);
6248 static BcStatus bc_program_stackLen(BcProgram *p)
6252 size_t len = p->results.len;
6254 res.t = BC_RESULT_TEMP;
6256 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6257 s = bc_num_ulong2num(&res.d.n, len);
6259 bc_vec_push(&p->results, &res);
6264 bc_num_free(&res.d.n);
6268 static BcStatus bc_program_asciify(BcProgram *p)
6272 BcNum *num = NULL, n;
6273 char *str, *str2, c;
6274 size_t len = p->strs.len, idx;
6277 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6278 r = bc_vec_top(&p->results);
6280 s = bc_program_num(p, r, &num, false);
6283 if (BC_PROG_NUM(r, num)) {
6285 bc_num_init(&n, BC_NUM_DEF_SIZE);
6286 bc_num_copy(&n, num);
6287 bc_num_truncate(&n, n.rdx);
6289 s = bc_num_mod(&n, &p->strmb, &n, 0);
6290 if (s) goto num_err;
6291 s = bc_num_ulong(&n, &val);
6292 if (s) goto num_err;
6299 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6300 str2 = *((char **) bc_vec_item(&p->strs, idx));
6308 str2 = xstrdup(str);
6309 bc_program_addFunc(p, str2, &idx);
6311 if (idx != len + BC_PROG_REQ_FUNCS) {
6313 for (idx = 0; idx < p->strs.len; ++idx) {
6314 if (!strcmp(*((char **) bc_vec_item(&p->strs, idx)), str)) {
6323 bc_vec_push(&p->strs, &str);
6325 res.t = BC_RESULT_STR;
6327 bc_vec_pop(&p->results);
6328 bc_vec_push(&p->results, &res);
6330 return BC_STATUS_SUCCESS;
6337 static BcStatus bc_program_printStream(BcProgram *p)
6345 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6346 r = bc_vec_top(&p->results);
6348 s = bc_program_num(p, r, &n, false);
6351 if (BC_PROG_NUM(r, n))
6352 s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
6354 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6355 str = *((char **) bc_vec_item(&p->strs, idx));
6362 static BcStatus bc_program_nquit(BcProgram *p)
6369 s = bc_program_prep(p, &opnd, &num);
6371 s = bc_num_ulong(num, &val);
6374 bc_vec_pop(&p->results);
6376 if (p->stack.len < val)
6377 return BC_STATUS_EXEC_STACK;
6378 else if (p->stack.len == val)
6379 return BC_STATUS_QUIT;
6381 bc_vec_npop(&p->stack, val);
6386 static BcStatus bc_program_execStr(BcProgram *p, char *code, size_t *bgn,
6389 BcStatus s = BC_STATUS_SUCCESS;
6399 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6401 r = bc_vec_top(&p->results);
6406 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6408 if (code[*bgn] == BC_PARSE_STREND)
6411 else_name = bc_program_name(code, bgn);
6413 exec = r->d.n.len != 0;
6417 else if (else_name != NULL) {
6423 bc_program_search(p, name, &v, true);
6430 if (!exec) goto exit;
6431 if (!BC_PROG_STR(n)) {
6432 s = BC_STATUS_EXEC_BAD_TYPE;
6440 if (r->t == BC_RESULT_STR)
6442 else if (r->t == BC_RESULT_VAR) {
6443 s = bc_program_num(p, r, &n, false);
6444 if (s || !BC_PROG_STR(n)) goto exit;
6451 fidx = sidx + BC_PROG_REQ_FUNCS;
6453 str = bc_vec_item(&p->strs, sidx);
6454 f = bc_vec_item(&p->fns, fidx);
6456 if (f->code.len == 0) {
6458 p->parse_init(&prs, p, fidx);
6459 s = bc_parse_text(&prs, *str);
6461 s = p->parse_expr(&prs, BC_PARSE_NOCALL);
6464 if (prs.l.t.t != BC_LEX_EOF) {
6465 s = BC_STATUS_PARSE_BAD_EXP;
6469 bc_parse_free(&prs);
6473 ip.len = p->results.len;
6476 bc_vec_pop(&p->results);
6477 bc_vec_push(&p->stack, &ip);
6479 return BC_STATUS_SUCCESS;
6482 bc_parse_free(&prs);
6483 f = bc_vec_item(&p->fns, fidx);
6484 bc_vec_npop(&f->code, f->code.len);
6486 bc_vec_pop(&p->results);
6491 static BcStatus bc_program_pushGlobal(BcProgram *p, char inst)
6497 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6498 if (inst == BC_INST_IBASE)
6499 val = (unsigned long) p->ib_t;
6500 else if (inst == BC_INST_SCALE)
6501 val = (unsigned long) p->scale;
6503 val = (unsigned long) p->ob_t;
6505 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6506 s = bc_num_ulong2num(&res.d.n, val);
6508 bc_vec_push(&p->results, &res);
6513 bc_num_free(&res.d.n);
6517 static void bc_program_free(BcProgram *p)
6519 bc_num_free(&p->ib);
6520 bc_num_free(&p->ob);
6521 bc_num_free(&p->hexb);
6523 bc_num_free(&p->strmb);
6525 bc_vec_free(&p->fns);
6526 bc_vec_free(&p->fn_map);
6527 bc_vec_free(&p->vars);
6528 bc_vec_free(&p->var_map);
6529 bc_vec_free(&p->arrs);
6530 bc_vec_free(&p->arr_map);
6531 bc_vec_free(&p->strs);
6532 bc_vec_free(&p->consts);
6533 bc_vec_free(&p->results);
6534 bc_vec_free(&p->stack);
6535 bc_num_free(&p->last);
6536 bc_num_free(&p->zero);
6537 bc_num_free(&p->one);
6540 static void bc_program_init(BcProgram *p, size_t line_len, BcParseInit init,
6546 memset(p, 0, sizeof(BcProgram));
6547 memset(&ip, 0, sizeof(BcInstPtr));
6549 p->nchars = p->scale = 0;
6551 p->parse_init = init;
6552 p->parse_expr = expr;
6554 bc_num_init(&p->ib, BC_NUM_DEF_SIZE);
6558 bc_num_init(&p->ob, BC_NUM_DEF_SIZE);
6562 bc_num_init(&p->hexb, BC_NUM_DEF_SIZE);
6563 bc_num_ten(&p->hexb);
6567 bc_num_init(&p->strmb, BC_NUM_DEF_SIZE);
6568 bc_num_ulong2num(&p->strmb, UCHAR_MAX + 1);
6571 bc_num_init(&p->last, BC_NUM_DEF_SIZE);
6572 bc_num_zero(&p->last);
6574 bc_num_init(&p->zero, BC_NUM_DEF_SIZE);
6575 bc_num_zero(&p->zero);
6577 bc_num_init(&p->one, BC_NUM_DEF_SIZE);
6578 bc_num_one(&p->one);
6580 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
6581 bc_map_init(&p->fn_map);
6583 bc_program_addFunc(p, xstrdup(bc_func_main), &idx);
6584 bc_program_addFunc(p, xstrdup(bc_func_read), &idx);
6586 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
6587 bc_map_init(&p->var_map);
6589 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
6590 bc_map_init(&p->arr_map);
6592 bc_vec_init(&p->strs, sizeof(char *), bc_string_free);
6593 bc_vec_init(&p->consts, sizeof(char *), bc_string_free);
6594 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
6595 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
6596 bc_vec_push(&p->stack, &ip);
6599 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx)
6602 BcId entry, *entry_ptr;
6606 entry.idx = p->fns.len;
6608 s = bc_map_insert(&p->fn_map, &entry, idx);
6611 entry_ptr = bc_vec_item(&p->fn_map, *idx);
6612 *idx = entry_ptr->idx;
6614 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6616 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
6618 // We need to reset these, so the function can be repopulated.
6620 bc_vec_npop(&func->autos, func->autos.len);
6621 bc_vec_npop(&func->code, func->code.len);
6622 bc_vec_npop(&func->labels, func->labels.len);
6626 bc_vec_push(&p->fns, &f);
6630 static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
6635 bc_vec_npop(&p->stack, p->stack.len - 1);
6636 bc_vec_npop(&p->results, p->results.len);
6638 f = bc_vec_item(&p->fns, 0);
6639 ip = bc_vec_top(&p->stack);
6640 ip->idx = f->code.len;
6642 if (!s && bcg.signe && !bcg.tty) return BC_STATUS_QUIT;
6644 bcg.sigc += bcg.signe;
6645 bcg.signe = bcg.sig != bcg.sigc;
6647 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6649 fputs(bc_program_ready_msg, stderr);
6651 s = BC_STATUS_SUCCESS;
6660 static BcStatus bc_program_exec(BcProgram *p)
6662 BcStatus s = BC_STATUS_SUCCESS;
6666 BcInstPtr *ip = bc_vec_top(&p->stack);
6667 BcFunc *func = bc_vec_item(&p->fns, ip->func);
6668 char *code = func->code.v;
6671 while (!s && ip->idx < func->code.len) {
6673 char inst = code[(ip->idx)++];
6678 case BC_INST_JUMP_ZERO:
6680 s = bc_program_prep(p, &ptr, &num);
6682 cond = !bc_num_cmp(num, &p->zero);
6683 bc_vec_pop(&p->results);
6689 idx = bc_program_index(code, &ip->idx);
6690 addr = bc_vec_item(&func->labels, idx);
6691 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6697 s = bc_program_call(p, code, &ip->idx);
6701 case BC_INST_INC_PRE:
6702 case BC_INST_DEC_PRE:
6703 case BC_INST_INC_POST:
6704 case BC_INST_DEC_POST:
6706 s = bc_program_incdec(p, inst);
6719 s = bc_program_return(p, inst);
6723 case BC_INST_BOOL_OR:
6724 case BC_INST_BOOL_AND:
6726 case BC_INST_REL_EQ:
6727 case BC_INST_REL_LE:
6728 case BC_INST_REL_GE:
6729 case BC_INST_REL_NE:
6730 case BC_INST_REL_LT:
6731 case BC_INST_REL_GT:
6733 s = bc_program_logical(p, inst);
6739 s = bc_program_read(p);
6745 s = bc_program_pushVar(p, code, &ip->idx, false, false);
6749 case BC_INST_ARRAY_ELEM:
6752 s = bc_program_pushArray(p, code, &ip->idx, inst);
6758 r.t = BC_RESULT_LAST;
6759 bc_vec_push(&p->results, &r);
6767 s = bc_program_pushGlobal(p, inst);
6771 case BC_INST_SCALE_FUNC:
6772 case BC_INST_LENGTH:
6775 s = bc_program_builtin(p, inst);
6781 r.t = BC_RESULT_CONSTANT;
6782 r.d.id.idx = bc_program_index(code, &ip->idx);
6783 bc_vec_push(&p->results, &r);
6789 if (!BC_PROG_STACK(&p->results, 1))
6790 s = BC_STATUS_EXEC_STACK;
6792 bc_vec_pop(&p->results);
6796 case BC_INST_POP_EXEC:
6798 bc_vec_pop(&p->stack);
6803 case BC_INST_PRINT_POP:
6804 case BC_INST_PRINT_STR:
6806 s = bc_program_print(p, inst, 0);
6812 r.t = BC_RESULT_STR;
6813 r.d.id.idx = bc_program_index(code, &ip->idx);
6814 bc_vec_push(&p->results, &r);
6819 case BC_INST_MULTIPLY:
6820 case BC_INST_DIVIDE:
6821 case BC_INST_MODULUS:
6825 s = bc_program_op(p, inst);
6829 case BC_INST_BOOL_NOT:
6831 s = bc_program_prep(p, &ptr, &num);
6834 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6835 (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6836 bc_program_retire(p, &r, BC_RESULT_TEMP);
6843 s = bc_program_negate(p);
6848 case BC_INST_ASSIGN_POWER:
6849 case BC_INST_ASSIGN_MULTIPLY:
6850 case BC_INST_ASSIGN_DIVIDE:
6851 case BC_INST_ASSIGN_MODULUS:
6852 case BC_INST_ASSIGN_PLUS:
6853 case BC_INST_ASSIGN_MINUS:
6855 case BC_INST_ASSIGN:
6857 s = bc_program_assign(p, inst);
6861 case BC_INST_MODEXP:
6863 s = bc_program_modexp(p);
6867 case BC_INST_DIVMOD:
6869 s = bc_program_divmod(p);
6873 case BC_INST_EXECUTE:
6874 case BC_INST_EXEC_COND:
6876 cond = inst == BC_INST_EXEC_COND;
6877 s = bc_program_execStr(p, code, &ip->idx, cond);
6881 case BC_INST_PRINT_STACK:
6883 for (idx = 0; !s && idx < p->results.len; ++idx)
6884 s = bc_program_print(p, BC_INST_PRINT, idx);
6888 case BC_INST_CLEAR_STACK:
6890 bc_vec_npop(&p->results, p->results.len);
6894 case BC_INST_STACK_LEN:
6896 s = bc_program_stackLen(p);
6900 case BC_INST_DUPLICATE:
6902 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6903 ptr = bc_vec_top(&p->results);
6904 bc_result_copy(&r, ptr);
6905 bc_vec_push(&p->results, &r);
6913 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
6915 ptr = bc_vec_item_rev(&p->results, 0);
6916 ptr2 = bc_vec_item_rev(&p->results, 1);
6917 memcpy(&r, ptr, sizeof(BcResult));
6918 memcpy(ptr, ptr2, sizeof(BcResult));
6919 memcpy(ptr2, &r, sizeof(BcResult));
6924 case BC_INST_ASCIIFY:
6926 s = bc_program_asciify(p);
6930 case BC_INST_PRINT_STREAM:
6932 s = bc_program_printStream(p);
6937 case BC_INST_PUSH_VAR:
6939 bool copy = inst == BC_INST_LOAD;
6940 s = bc_program_pushVar(p, code, &ip->idx, true, copy);
6944 case BC_INST_PUSH_TO_VAR:
6946 char *name = bc_program_name(code, &ip->idx);
6947 s = bc_program_copyToVar(p, name, true);
6954 if (p->stack.len <= 2)
6957 bc_vec_npop(&p->stack, 2);
6963 s = bc_program_nquit(p);
6969 if ((s && s != BC_STATUS_QUIT) || bcg.signe) s = bc_program_reset(p, s);
6971 // If the stack has changed, pointers may be invalid.
6972 ip = bc_vec_top(&p->stack);
6973 func = bc_vec_item(&p->fns, ip->func);
6974 code = func->code.v;
6980 #if ENABLE_FEATURE_BC_SIGNALS
6981 static void bc_vm_sig(int sig)
6984 size_t len = strlen(bcg.sig_msg);
6985 if (sig == SIGINT && write(2, bcg.sig_msg, len) == (ssize_t) len) {
6986 bcg.signe = bcg.sig == bcg.sigc;
6987 bcg.sig += bcg.signe;
6993 static void bc_vm_info(void)
6995 printf("%s "BB_VER"\n"
6996 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6997 "Report bugs at: https://github.com/gavinhoward/bc\n"
6998 "This is free software with ABSOLUTELY NO WARRANTY\n"
7002 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
7004 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
7006 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7007 fprintf(stderr, " %s", file);
7008 fprintf(stderr, bc_err_line + 4 * !line, line);
7010 return s * (!bcg.ttyin || !!strcmp(file, bc_program_stdin_name));
7014 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
7017 int p = (int) bcg.posix, w = (int) bcg.warn;
7018 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
7020 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
7022 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7023 if (msg) fprintf(stderr, " %s\n", msg);
7024 fprintf(stderr, " %s", file);
7025 fprintf(stderr, bc_err_line + 4 * !line, line);
7027 return s * (!bcg.ttyin && !!p);
7030 static void bc_vm_envArgs(BcVm *vm)
7033 char *env_args = getenv(bc_args_env_name), *buf;
7035 if (!env_args) return;
7037 vm->env_args = xstrdup(env_args);
7040 bc_vec_init(&v, sizeof(char *), NULL);
7041 bc_vec_push(&v, &bc_args_env_name);
7044 if (!isspace(*buf)) {
7045 bc_vec_push(&v, &buf);
7046 while (*buf != 0 && !isspace(*buf)) ++buf;
7047 if (*buf != 0) (*(buf++)) = '\0';
7053 bc_args((int) v.len, (char **) v.v, &vm->flags, &vm->files);
7059 static size_t bc_vm_envLen(const char *var)
7061 char *lenv = getenv(var);
7062 size_t i, len = BC_NUM_PRINT_WIDTH;
7065 if (!lenv) return len;
7069 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
7071 len = (size_t) atoi(lenv) - 1;
7072 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
7075 len = BC_NUM_PRINT_WIDTH;
7080 static BcStatus bc_vm_process(BcVm *vm, const char *text)
7082 BcStatus s = bc_parse_text(&vm->prs, text);
7084 s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line);
7087 while (vm->prs.l.t.t != BC_LEX_EOF) {
7089 s = vm->prs.parse(&vm->prs);
7091 if (s == BC_STATUS_LIMITS) {
7094 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
7095 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
7096 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
7097 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
7098 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
7099 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
7100 printf("Max Exponent = %lu\n", BC_MAX_EXP);
7101 printf("Number of Vars = %lu\n", BC_MAX_VARS);
7104 s = BC_STATUS_SUCCESS;
7107 if (s == BC_STATUS_QUIT) return s;
7108 s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line);
7113 if (BC_PARSE_CAN_EXEC(&vm->prs)) {
7114 s = bc_program_exec(&vm->prog);
7115 if (!s && bcg.tty) fflush(stdout);
7116 if (s && s != BC_STATUS_QUIT)
7117 s = bc_vm_error(bc_program_reset(&vm->prog, s), vm->prs.l.f, 0);
7123 static BcStatus bc_vm_file(BcVm *vm, const char *file)
7130 vm->prog.file = file;
7131 s = bc_read_file(file, &data);
7132 if (s) return bc_vm_error(s, file, 0);
7134 bc_lex_file(&vm->prs.l, file);
7135 s = bc_vm_process(vm, data);
7138 main_func = bc_vec_item(&vm->prog.fns, BC_PROG_MAIN);
7139 ip = bc_vec_item(&vm->prog.stack, 0);
7141 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7148 static BcStatus bc_vm_stdin(BcVm *vm)
7150 BcStatus s = BC_STATUS_SUCCESS;
7153 size_t len, i, str = 0;
7154 bool comment = false, notend;
7156 vm->prog.file = bc_program_stdin_name;
7157 bc_lex_file(&vm->prs.l, bc_program_stdin_name);
7159 bc_vec_init(&buffer, sizeof(char), NULL);
7160 bc_vec_init(&buf, sizeof(char), NULL);
7161 bc_vec_pushByte(&buffer, '\0');
7163 // This loop is complex because the vm tries not to send any lines that end
7164 // with a backslash to the parser. The reason for that is because the parser
7165 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7166 // case, and for strings and comments, the parser will expect more stuff.
7167 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7169 char *string = buf.v;
7174 if (str && buf.v[0] == vm->exe.send)
7176 else if (buf.v[0] == vm->exe.sbgn)
7179 else if (len > 1 || comment) {
7181 for (i = 0; i < len; ++i) {
7183 notend = len > i + 1;
7186 if (i - 1 > len || string[i - 1] != '\\') {
7187 if (vm->exe.sbgn == vm->exe.send)
7188 str ^= c == vm->exe.sbgn;
7189 else if (c == vm->exe.send)
7191 else if (c == vm->exe.sbgn)
7195 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7199 else if (c == '*' && notend && comment && string[i + 1] == '/')
7203 if (str || comment || string[len - 2] == '\\') {
7204 bc_vec_concat(&buffer, buf.v);
7209 bc_vec_concat(&buffer, buf.v);
7210 s = bc_vm_process(vm, buffer.v);
7213 bc_vec_npop(&buffer, buffer.len);
7216 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, vm->prs.l.f, 0);
7218 // INPUT_EOF will always happen when stdin is
7219 // closed. It's not a problem in that case.
7220 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7221 s = BC_STATUS_SUCCESS;
7224 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, vm->prs.l.f,
7227 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, vm->prs.l.f,
7232 bc_vec_free(&buffer);
7236 static BcStatus bc_vm_exec(BcVm *vm)
7238 BcStatus s = BC_STATUS_SUCCESS;
7242 if (vm->flags & BC_FLAG_L) {
7244 bc_lex_file(&vm->prs.l, bc_lib_name);
7245 s = bc_parse_text(&vm->prs, bc_lib);
7247 while (!s && vm->prs.l.t.t != BC_LEX_EOF) s = vm->prs.parse(&vm->prs);
7250 s = bc_program_exec(&vm->prog);
7255 for (i = 0; !s && i < vm->files.len; ++i)
7256 s = bc_vm_file(vm, *((char **) bc_vec_item(&vm->files, i)));
7257 if (s && s != BC_STATUS_QUIT) return s;
7259 if (IS_BC || !vm->files.len) s = bc_vm_stdin(vm);
7260 if (!s && !BC_PARSE_CAN_EXEC(&vm->prs)) s = bc_vm_process(vm, "");
7262 if (s == BC_STATUS_QUIT)
7263 s = BC_STATUS_SUCCESS;
7267 static void bc_vm_free(BcVm *vm)
7269 bc_vec_free(&vm->files);
7270 bc_program_free(&vm->prog);
7271 bc_parse_free(&vm->prs);
7275 static void bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len)
7277 size_t len = bc_vm_envLen(env_len);
7278 #if ENABLE_FEATURE_BC_SIGNALS
7279 struct sigaction sa;
7281 sigemptyset(&sa.sa_mask);
7282 sa.sa_handler = bc_vm_sig;
7284 sigaction(SIGINT, &sa, NULL);
7287 memset(vm, 0, sizeof(BcVm));
7291 vm->env_args = NULL;
7293 bc_vec_init(&vm->files, sizeof(char *), NULL);
7296 vm->flags |= BC_FLAG_S * IS_BC * (getenv("POSIXLY_CORRECT") != NULL);
7297 if (IS_BC) bc_vm_envArgs(vm);
7300 bc_program_init(&vm->prog, len, exe.init, exe.exp);
7301 exe.init(&vm->prs, &vm->prog, BC_PROG_MAIN);
7304 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
7305 const char *env_len)
7310 bc_vm_init(&vm, exe, env_len);
7311 bc_args(argc, argv, &vm.flags, &vm.files);
7313 bcg.ttyin = isatty(0);
7314 bcg.tty = bcg.ttyin || (vm.flags & BC_FLAG_I) || isatty(1);
7317 bcg.posix = vm.flags & BC_FLAG_S;
7318 bcg.warn = vm.flags & BC_FLAG_W;
7321 bcg.exreg = vm.flags & BC_FLAG_X;
7324 if (bcg.ttyin && !(vm.flags & BC_FLAG_Q)) bc_vm_info();
7325 st = bc_vm_exec(&vm);
7332 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7333 int bc_main(int argc, char **argv)
7337 # if ENABLE_FEATURE_BC_SIGNALS
7338 bcg.sig_msg = "\ninterrupt (type \"quit\" to exit)\n";
7341 exec.init = bc_parse_init;
7342 exec.exp = bc_parse_expression;
7343 exec.sbgn = exec.send = '"';
7345 return bc_vm_run(argc, argv, exec, "BC_LINE_LENGTH");
7350 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7351 int dc_main(int argc, char **argv)
7355 # if ENABLE_FEATURE_BC_SIGNALS
7356 bcg.sig_msg = "\ninterrupt (type \"q\" to exit)\n";
7359 exec.init = dc_parse_init;
7360 exec.exp = dc_parse_expr;
7364 return bc_vm_run(argc, argv, exec, "DC_LINE_LENGTH");