1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //usage:#define bc_trivial_usage
118 //usage: "EXPRESSION...\n"
119 //usage: "function_definition\n"
121 //usage:#define bc_full_usage "\n\n"
122 //usage: "See www.gnu.org/software/bc/manual/bc.html\n"
124 //usage:#define bc_example_usage
125 //usage: "3 + 4.129\n"
126 //usage: "1903 - 2893\n"
127 //usage: "-129 * 213.28935\n"
128 //usage: "12 / -1932\n"
130 //usage: "34 ^ 189\n"
131 //usage: "scale = 13\n"
132 //usage: "ibase = 2\n"
133 //usage: "obase = A\n"
135 //usage:#define dc_trivial_usage
136 //usage: "EXPRESSION..."
138 //usage:#define dc_full_usage "\n\n"
139 //usage: "Tiny RPN calculator. Operations:\n"
140 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
141 //usage: "modular exponentiation,\n"
142 //usage: "p - print top of the stack (without popping),\n"
143 //usage: "f - print entire stack,\n"
144 //usage: "k - pop the value and set the precision.\n"
145 //usage: "i - pop the value and set input radix.\n"
146 //usage: "o - pop the value and set output radix.\n"
147 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
149 //usage:#define dc_example_usage
150 //usage: "$ dc 2 2 + p\n"
152 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
154 //usage: "$ dc 0 1 and p\n"
156 //usage: "$ dc 0 1 or p\n"
158 //usage: "$ echo 72 9 div 8 mul p | dc\n"
163 typedef enum BcStatus {
170 BC_STATUS_PATH_IS_DIR,
172 BC_STATUS_LEX_BAD_CHAR,
173 BC_STATUS_LEX_NO_STRING_END,
174 BC_STATUS_LEX_NO_COMMENT_END,
177 BC_STATUS_LEX_EXTENDED_REG,
180 BC_STATUS_PARSE_BAD_TOKEN,
181 BC_STATUS_PARSE_BAD_EXP,
182 BC_STATUS_PARSE_EMPTY_EXP,
183 BC_STATUS_PARSE_BAD_PRINT,
184 BC_STATUS_PARSE_BAD_FUNC,
185 BC_STATUS_PARSE_BAD_ASSIGN,
186 BC_STATUS_PARSE_NO_AUTO,
187 BC_STATUS_PARSE_DUPLICATE_LOCAL,
188 BC_STATUS_PARSE_NO_BLOCK_END,
190 BC_STATUS_MATH_NEGATIVE,
191 BC_STATUS_MATH_NON_INTEGER,
192 BC_STATUS_MATH_OVERFLOW,
193 BC_STATUS_MATH_DIVIDE_BY_ZERO,
194 BC_STATUS_MATH_BAD_STRING,
196 BC_STATUS_EXEC_FILE_ERR,
197 BC_STATUS_EXEC_MISMATCHED_PARAMS,
198 BC_STATUS_EXEC_UNDEFINED_FUNC,
199 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
200 BC_STATUS_EXEC_NUM_LEN,
201 BC_STATUS_EXEC_NAME_LEN,
202 BC_STATUS_EXEC_STRING_LEN,
203 BC_STATUS_EXEC_ARRAY_LEN,
204 BC_STATUS_EXEC_BAD_IBASE,
205 BC_STATUS_EXEC_BAD_SCALE,
206 BC_STATUS_EXEC_BAD_READ_EXPR,
207 BC_STATUS_EXEC_REC_READ,
208 BC_STATUS_EXEC_BAD_TYPE,
209 BC_STATUS_EXEC_BAD_OBASE,
210 BC_STATUS_EXEC_SIGNAL,
211 BC_STATUS_EXEC_STACK,
213 BC_STATUS_VEC_OUT_OF_BOUNDS,
214 BC_STATUS_VEC_ITEM_EXISTS,
217 BC_STATUS_POSIX_NAME_LEN,
218 BC_STATUS_POSIX_COMMENT,
219 BC_STATUS_POSIX_BAD_KW,
222 BC_STATUS_POSIX_BOOL,
223 BC_STATUS_POSIX_REL_POS,
224 BC_STATUS_POSIX_MULTIREL,
225 BC_STATUS_POSIX_FOR1,
226 BC_STATUS_POSIX_FOR2,
227 BC_STATUS_POSIX_FOR3,
228 BC_STATUS_POSIX_BRACE,
234 BC_STATUS_INVALID_OPTION,
238 #define BC_ERR_IDX_VM (0)
239 #define BC_ERR_IDX_LEX (1)
240 #define BC_ERR_IDX_PARSE (2)
241 #define BC_ERR_IDX_MATH (3)
242 #define BC_ERR_IDX_EXEC (4)
243 #define BC_ERR_IDX_VEC (5)
245 #define BC_ERR_IDX_POSIX (6)
248 #define BC_VEC_INVALID_IDX ((size_t) -1)
249 #define BC_VEC_START_CAP (1 << 5)
251 typedef void (*BcVecFree)(void *);
252 typedef int (*BcVecCmp)(const void *, const void *);
254 typedef struct BcVec {
262 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
263 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
265 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
267 #define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
269 typedef signed char BcDig;
271 typedef struct BcNum {
279 #define BC_NUM_MIN_BASE ((unsigned long) 2)
280 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
281 #define BC_NUM_DEF_SIZE (16)
282 #define BC_NUM_PRINT_WIDTH (69)
284 #define BC_NUM_KARATSUBA_LEN (32)
286 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
287 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
288 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
289 #define BC_NUM_AREQ(a, b) \
290 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
291 #define BC_NUM_MREQ(a, b, scale) \
292 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
294 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
295 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
297 static void bc_num_init(BcNum *n, size_t req);
298 static void bc_num_expand(BcNum *n, size_t req);
299 static void bc_num_copy(BcNum *d, BcNum *s);
300 static void bc_num_free(void *num);
302 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
303 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val);
305 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
308 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
309 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
310 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
311 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
312 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
315 typedef enum BcInst {
345 BC_INST_ASSIGN_POWER,
346 BC_INST_ASSIGN_MULTIPLY,
347 BC_INST_ASSIGN_DIVIDE,
348 BC_INST_ASSIGN_MODULUS,
350 BC_INST_ASSIGN_MINUS,
396 BC_INST_PRINT_STREAM,
411 BC_INST_INVALID = -1,
416 typedef struct BcId {
421 typedef struct BcFunc {
428 typedef enum BcResultType {
433 BC_RESULT_ARRAY_ELEM,
442 // These are between to calculate ibase, obase, and last from instructions.
450 typedef union BcResultData {
456 typedef struct BcResult {
461 typedef struct BcInstPtr {
467 static void bc_array_expand(BcVec *a, size_t len);
468 static int bc_id_cmp(const void *e1, const void *e2);
470 // BC_LEX_NEG is not used in lexing; it is only for parsing.
471 typedef enum BcLexType {
499 BC_LEX_OP_ASSIGN_POWER,
500 BC_LEX_OP_ASSIGN_MULTIPLY,
501 BC_LEX_OP_ASSIGN_DIVIDE,
502 BC_LEX_OP_ASSIGN_MODULUS,
503 BC_LEX_OP_ASSIGN_PLUS,
504 BC_LEX_OP_ASSIGN_MINUS,
578 typedef BcStatus (*BcLexNext)(struct BcLex *);
580 typedef struct BcLex {
599 #define BC_PARSE_STREND ((char) UCHAR_MAX)
601 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
602 #define bc_parse_updateFunc(p, f) \
603 ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f))))
605 #define BC_PARSE_REL (1 << 0)
606 #define BC_PARSE_PRINT (1 << 1)
607 #define BC_PARSE_NOCALL (1 << 2)
608 #define BC_PARSE_NOREAD (1 << 3)
609 #define BC_PARSE_ARRAY (1 << 4)
611 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
612 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
614 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
615 #define BC_PARSE_FUNC_INNER(parse) \
616 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
618 #define BC_PARSE_FLAG_FUNC (1 << 1)
619 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
621 #define BC_PARSE_FLAG_BODY (1 << 2)
622 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
624 #define BC_PARSE_FLAG_LOOP (1 << 3)
625 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
627 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
628 #define BC_PARSE_LOOP_INNER(parse) \
629 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
631 #define BC_PARSE_FLAG_IF (1 << 5)
632 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
634 #define BC_PARSE_FLAG_ELSE (1 << 6)
635 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
637 #define BC_PARSE_FLAG_IF_END (1 << 7)
638 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
640 #define BC_PARSE_CAN_EXEC(parse) \
641 (!(BC_PARSE_TOP_FLAG(parse) & \
642 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
643 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
644 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
646 typedef struct BcOp {
651 typedef struct BcParseNext {
656 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
657 #define BC_PARSE_NEXT(a, ...) \
659 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
666 typedef void (*BcParseInit)(struct BcParse *, struct BcProgram *, size_t);
667 typedef BcStatus (*BcParseParse)(struct BcParse *);
668 typedef BcStatus (*BcParseExpr)(struct BcParse *, uint8_t);
670 typedef struct BcParse {
683 struct BcProgram *prog;
694 BcStatus bc_main(int argc, char *argv[]);
696 typedef struct BcLexKeyword {
702 #define BC_LEX_KW_ENTRY(a, b, c) \
704 .name = a, .len = (b), .posix = (c) \
707 static BcStatus bc_lex_token(BcLex *l);
709 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
710 #define BC_PARSE_LEAF(p, rparen) \
711 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
712 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
714 // We can calculate the conversion between tokens and exprs by subtracting the
715 // position of the first operator in the lex enum and adding the position of the
716 // first in the expr enum. Note: This only works for binary operators.
717 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
719 static BcStatus bc_parse_parse(BcParse *p);
720 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
726 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
728 BcStatus dc_main(int argc, char *argv[]);
730 static BcStatus dc_lex_token(BcLex *l);
732 static void dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
733 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
737 typedef struct BcProgram {
776 BcParseInit parse_init;
777 BcParseExpr parse_expr;
781 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
783 #define BC_PROG_MAIN (0)
784 #define BC_PROG_READ (1)
787 #define BC_PROG_REQ_FUNCS (2)
790 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
791 #define BC_PROG_NUM(r, n) \
792 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
794 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
796 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx);
797 static BcStatus bc_program_reset(BcProgram *p, BcStatus s);
798 static BcStatus bc_program_exec(BcProgram *p);
800 #define BC_FLAG_X (1 << 0)
801 #define BC_FLAG_W (1 << 1)
802 #define BC_FLAG_V (1 << 2)
803 #define BC_FLAG_S (1 << 3)
804 #define BC_FLAG_Q (1 << 4)
805 #define BC_FLAG_L (1 << 5)
806 #define BC_FLAG_I (1 << 6)
808 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
809 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
811 #define BC_MAX_OBASE ((unsigned long) 999)
812 #define BC_MAX_DIM ((unsigned long) INT_MAX)
813 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
814 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
815 #define BC_MAX_NAME BC_MAX_STRING
816 #define BC_MAX_NUM BC_MAX_STRING
817 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
818 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
820 typedef struct BcVmExe {
827 typedef struct BcVm {
840 typedef struct BcGlobals {
853 #if ENABLE_FEATURE_BC_SIGNALS
855 #endif // ENABLE_FEATURE_BC_SIGNALS
862 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
866 static void bc_vm_exit(BcStatus s);
867 static void bc_vm_printf(FILE *restrict f, const char *fmt, ...);
868 static void bc_vm_puts(const char *str, FILE *restrict f);
869 static void bc_vm_putchar(int c);
870 static void bc_vm_fflush(FILE *restrict f);
872 static void bc_vm_info(const char *const help);
873 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
874 const char *env_len);
876 static BcGlobals bcg;
879 static const char bc_name[] = "bc";
880 #if ENABLE_FEATURE_BC_SIGNALS
881 static const char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n";
882 #endif // ENABLE_FEATURE_BC_SIGNALS
886 static const char dc_name[] = "dc";
887 #if ENABLE_FEATURE_BC_SIGNALS
888 static const char dc_sig_msg[] = "\ninterrupt (type \"q\" to exit)\n";
889 #endif // ENABLE_FEATURE_BC_SIGNALS
892 static const char bc_copyright[] =
893 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
894 "Report bugs at: https://github.com/gavinhoward/bc\n\n"
895 "This is free software with ABSOLUTELY NO WARRANTY.\n";
897 static const char* const bc_args_env_name = "BC_ENV_ARGS";
899 static const char bc_err_fmt[] = "\n%s error: %s\n";
900 static const char bc_warn_fmt[] = "\n%s warning: %s\n";
901 static const char bc_err_line[] = ":%zu\n\n";
903 static const char *bc_errs[] = {
915 static const uint8_t bc_err_ids[] = {
916 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
917 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
921 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
922 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
923 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
928 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
929 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
930 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
931 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
933 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
935 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
936 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
937 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
939 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
942 static const char *bc_err_msgs[] = {
945 "memory allocation error",
948 "path is a directory:",
951 "string end could not be found",
952 "comment end could not be found",
961 "bad print statement",
962 "bad function definition",
963 "bad assignment: left side must be scale, ibase, "
964 "obase, last, var, or array element",
965 "no auto variable found",
966 "function parameter or auto var has the same name as another",
967 "block end could not be found",
970 "non integer number",
975 "could not open file:",
976 "mismatched parameters",
977 "undefined function",
978 "file is not executable:",
979 "number too long: must be [1, BC_NUM_MAX]",
980 "name too long: must be [1, BC_NAME_MAX]",
981 "string too long: must be [1, BC_STRING_MAX]",
982 "array too long; must be [1, BC_DIM_MAX]",
983 "bad ibase; must be [2, 16]",
984 "bad scale; must be [0, BC_SCALE_MAX]",
985 "bad read() expression",
986 "read() call inside of a read() call",
987 "variable is wrong type",
988 "bad obase; must be [2, BC_BASE_MAX]",
989 "signal caught and not handled",
990 "stack has too few elements",
992 "index is out of bounds",
993 "item already exists",
996 "POSIX only allows one character names; the following is bad:",
997 "POSIX does not allow '#' script comments",
998 "POSIX does not allow the following keyword:",
999 "POSIX does not allow a period ('.') as a shortcut for the last result",
1000 "POSIX requires parentheses around return expressions",
1001 "POSIX does not allow boolean operators; the following is bad:",
1002 "POSIX does not allow comparison operators outside if or loops",
1003 "POSIX requires exactly one comparison operator per condition",
1004 "POSIX does not allow an empty init expression in a for loop",
1005 "POSIX does not allow an empty condition expression in a for loop",
1006 "POSIX does not allow an empty update expression in a for loop",
1007 "POSIX requires the left brace be on the same line as the function header",
1012 static const char bc_func_main[] = "(main)";
1013 static const char bc_func_read[] = "(read)";
1016 static const BcLexKeyword bc_lex_kws[20] = {
1017 BC_LEX_KW_ENTRY("auto", 4, true),
1018 BC_LEX_KW_ENTRY("break", 5, true),
1019 BC_LEX_KW_ENTRY("continue", 8, false),
1020 BC_LEX_KW_ENTRY("define", 6, true),
1021 BC_LEX_KW_ENTRY("else", 4, false),
1022 BC_LEX_KW_ENTRY("for", 3, true),
1023 BC_LEX_KW_ENTRY("halt", 4, false),
1024 BC_LEX_KW_ENTRY("ibase", 5, true),
1025 BC_LEX_KW_ENTRY("if", 2, true),
1026 BC_LEX_KW_ENTRY("last", 4, false),
1027 BC_LEX_KW_ENTRY("length", 6, true),
1028 BC_LEX_KW_ENTRY("limits", 6, false),
1029 BC_LEX_KW_ENTRY("obase", 5, true),
1030 BC_LEX_KW_ENTRY("print", 5, false),
1031 BC_LEX_KW_ENTRY("quit", 4, true),
1032 BC_LEX_KW_ENTRY("read", 4, false),
1033 BC_LEX_KW_ENTRY("return", 6, true),
1034 BC_LEX_KW_ENTRY("scale", 5, true),
1035 BC_LEX_KW_ENTRY("sqrt", 4, true),
1036 BC_LEX_KW_ENTRY("while", 5, true),
1039 // This is an array that corresponds to token types. An entry is
1040 // true if the token is valid in an expression, false otherwise.
1041 static const bool bc_parse_exprs[] = {
1042 false, false, true, true, true, true, true, true, true, true, true, true,
1043 true, true, true, true, true, true, true, true, true, true, true, true,
1044 true, true, true, false, false, true, true, false, false, false, false,
1045 false, false, false, true, true, false, false, false, false, false, false,
1046 false, true, false, true, true, true, true, false, false, true, false, true,
1050 // This is an array of data for operators that correspond to token types.
1051 static const BcOp bc_parse_ops[] = {
1052 { 0, false }, { 0, false },
1055 { 3, true }, { 3, true }, { 3, true },
1056 { 4, true }, { 4, true },
1057 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1059 { 7, true }, { 7, true },
1060 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1061 { 5, false }, { 5, false },
1064 // These identify what tokens can come after expressions in certain cases.
1065 static const BcParseNext bc_parse_next_expr =
1066 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1067 static const BcParseNext bc_parse_next_param =
1068 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1069 static const BcParseNext bc_parse_next_print =
1070 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1071 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1072 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1073 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1074 static const BcParseNext bc_parse_next_read =
1075 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1079 static const BcLexType dc_lex_regs[] = {
1080 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1081 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1082 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1086 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1088 static const BcLexType dc_lex_tokens[] = {
1089 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1090 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1091 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1092 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1093 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1094 BC_LEX_INVALID, BC_LEX_INVALID,
1095 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1096 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1097 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1098 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1099 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1100 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1101 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1102 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1103 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1104 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1105 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1106 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1107 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1108 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1109 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1110 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1111 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1112 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1116 static const BcInst dc_parse_insts[] = {
1117 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1118 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1119 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1120 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1121 BC_INST_INVALID, BC_INST_INVALID,
1122 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1123 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1124 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1125 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1126 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1127 BC_INST_INVALID, BC_INST_INVALID,
1128 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1129 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1130 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1131 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1132 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1133 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1134 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1135 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1136 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1137 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1138 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1139 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1143 static const char bc_num_hex_digits[] = "0123456789ABCDEF";
1145 static const BcNumBinaryOp bc_program_ops[] = {
1146 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1149 static const char bc_program_stdin_name[] = "<stdin>";
1150 static const char bc_program_ready_msg[] = "ready for more input\n";
1153 static const char *bc_lib_name = "gen/lib.bc";
1155 static const char bc_lib[] = {
1156 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1157 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1158 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1159 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,
1160 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1161 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1162 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,
1163 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1164 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1165 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,
1166 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1167 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1168 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1169 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1170 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1171 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1172 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1173 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1174 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1175 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1176 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1177 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1178 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1179 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,
1180 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1181 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,
1182 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1183 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1184 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1185 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1186 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1187 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,
1188 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1189 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1190 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1191 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1192 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,
1193 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1194 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1195 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1196 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1197 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1198 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1199 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1200 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1201 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1202 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1203 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,
1204 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,
1205 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1206 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,
1207 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,
1208 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,
1209 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1210 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1211 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,
1212 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,
1213 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,
1214 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1215 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,
1216 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1217 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1218 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1219 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,
1220 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1221 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1222 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1223 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1224 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1225 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1226 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1227 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1228 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1229 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1230 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1231 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1232 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1233 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1234 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1235 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1239 static void bc_vec_grow(BcVec *v, size_t n)
1241 size_t cap = v->cap * 2;
1242 while (cap < v->len + n) cap *= 2;
1243 v->v = xrealloc(v->v, v->size * cap);
1247 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1250 v->cap = BC_VEC_START_CAP;
1253 v->v = xmalloc(esize * BC_VEC_START_CAP);
1256 static void bc_vec_expand(BcVec *v, size_t req)
1259 v->v = xrealloc(v->v, v->size * req);
1264 static void bc_vec_npop(BcVec *v, size_t n)
1269 size_t len = v->len - n;
1270 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1274 static void bc_vec_push(BcVec *v, const void *data)
1276 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1277 memmove(v->v + (v->size * v->len), data, v->size);
1281 static void bc_vec_pushByte(BcVec *v, char data)
1283 bc_vec_push(v, &data);
1286 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1289 bc_vec_push(v, data);
1294 if (v->len == v->cap) bc_vec_grow(v, 1);
1296 ptr = v->v + v->size * idx;
1298 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1299 memmove(ptr, data, v->size);
1303 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1305 bc_vec_npop(v, v->len);
1306 bc_vec_expand(v, len + 1);
1307 memcpy(v->v, str, len);
1310 bc_vec_pushByte(v, '\0');
1313 static void bc_vec_concat(BcVec *v, const char *str)
1317 if (v->len == 0) bc_vec_pushByte(v, '\0');
1319 len = v->len + strlen(str);
1321 if (v->cap < len) bc_vec_grow(v, len - v->len);
1327 static void *bc_vec_item(const BcVec *v, size_t idx)
1329 return v->v + v->size * idx;
1332 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1334 return v->v + v->size * (v->len - idx - 1);
1337 static void bc_vec_free(void *vec)
1339 BcVec *v = (BcVec *) vec;
1340 bc_vec_npop(v, v->len);
1344 static size_t bc_map_find(const BcVec *v, const void *ptr)
1346 size_t low = 0, high = v->len;
1348 while (low < high) {
1350 size_t mid = (low + high) / 2;
1351 BcId *id = bc_vec_item(v, mid);
1352 int result = bc_id_cmp(ptr, id);
1356 else if (result < 0)
1365 static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1367 BcStatus s = BC_STATUS_SUCCESS;
1369 *i = bc_map_find(v, ptr);
1372 bc_vec_push(v, ptr);
1373 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1374 s = BC_STATUS_VEC_ITEM_EXISTS;
1376 bc_vec_pushAt(v, ptr, *i);
1381 static size_t bc_map_index(const BcVec *v, const void *ptr)
1383 size_t i = bc_map_find(v, ptr);
1384 if (i >= v->len) return BC_VEC_INVALID_IDX;
1385 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1388 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1393 if (bcg.ttyin && !bcg.posix) {
1394 bc_vm_puts(prompt, stderr);
1395 bc_vm_fflush(stderr);
1398 bc_vec_npop(vec, vec->len);
1406 #if ENABLE_FEATURE_BC_SIGNALS
1407 if (errno == EINTR) {
1413 bc_vm_puts(bc_program_ready_msg, stderr);
1414 if (!bcg.posix) bc_vm_puts(prompt, stderr);
1415 bc_vm_fflush(stderr);
1420 #endif // ENABLE_FEATURE_BC_SIGNALS
1422 return BC_STATUS_IO_ERR;
1425 c = (signed char) i;
1426 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1427 bc_vec_push(vec, &c);
1430 bc_vec_pushByte(vec, '\0');
1432 return BC_STATUS_SUCCESS;
1435 static BcStatus bc_read_file(const char *path, char **buf)
1437 BcStatus s = BC_STATUS_BIN_FILE;
1438 size_t size = ((size_t) -1), read;
1440 *buf = xmalloc_open_read_close(path, &size);
1442 for (read = 0; read < size; ++read) {
1443 if (BC_READ_BIN_CHAR((*buf)[read])) goto read_err;
1446 return BC_STATUS_SUCCESS;
1453 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1454 static const char bc_args_lopt[] ALIGN1 =
1455 "extended-register\0"No_argument"x"
1456 "warn\0"No_argument"w"
1457 "version\0"No_argument"v"
1458 "standard\0"No_argument"s"
1459 "quiet\0"No_argument"q"
1460 "mathlib\0"No_argument"l"
1461 "interactive\0"No_argument"i";
1462 #endif // ENABLE_FEATURE_BC_LONG_OPTIONS
1464 static const char bc_args_opt[] ALIGN1 = "xwvsqli";
1466 static BcStatus bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
1468 BcStatus s = BC_STATUS_SUCCESS;
1470 bool do_exit = false;
1474 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1475 *flags = getopt32long(argv, bc_args_opt, bc_args_lopt);
1476 #else // ENABLE_FEATURE_BC_LONG_OPTIONS
1477 *flags = getopt32(argv, bc_args_opt);
1478 #endif // ENABLE_FEATURE_BC_LONG_OPTIONS
1480 if ((*flags) & BC_FLAG_V) bc_vm_info(NULL);
1481 if (do_exit) exit((int) s);
1482 if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1484 for (i = optind; i < argc; ++i) bc_vec_push(files, argv + i);
1489 static void bc_num_setToZero(BcNum *n, size_t scale)
1496 static void bc_num_zero(BcNum *n)
1498 bc_num_setToZero(n, 0);
1501 static void bc_num_one(BcNum *n)
1503 bc_num_setToZero(n, 0);
1508 static void bc_num_ten(BcNum *n)
1510 bc_num_setToZero(n, 0);
1516 static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1520 for (i = 0; !bcg.signe && i < len; ++i) {
1521 for (a[i] -= b[i], j = 0; !bcg.signe && a[i + j] < 0;) {
1526 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1529 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1533 for (i = len - 1; !bcg.signe && i < len && !(c = a[i] - b[i]); --i);
1534 return BC_NUM_NEG(i + 1, c < 0);
1537 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1539 size_t i, min, a_int, b_int, diff;
1540 BcDig *max_num, *min_num;
1541 bool a_max, neg = false;
1544 if (a == b) return 0;
1545 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1546 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1556 a_int = BC_NUM_INT(a);
1557 b_int = BC_NUM_INT(b);
1559 a_max = (a->rdx > b->rdx);
1561 if (a_int != 0) return (ssize_t) a_int;
1565 diff = a->rdx - b->rdx;
1566 max_num = a->num + diff;
1571 diff = b->rdx - a->rdx;
1572 max_num = b->num + diff;
1576 cmp = bc_num_compare(max_num, min_num, b_int + min);
1577 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1579 for (max_num -= diff, i = diff - 1; !bcg.signe && i < diff; --i) {
1580 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1586 static void bc_num_truncate(BcNum *n, size_t places)
1588 if (places == 0) return;
1594 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1598 static void bc_num_extend(BcNum *n, size_t places)
1600 size_t len = n->len + places;
1604 if (n->cap < len) bc_num_expand(n, len);
1606 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1607 memset(n->num, 0, sizeof(BcDig) * places);
1614 static void bc_num_clean(BcNum *n)
1616 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1619 else if (n->len < n->rdx)
1623 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1626 bc_num_extend(n, scale - n->rdx);
1628 bc_num_truncate(n, n->rdx - scale);
1631 if (n->len != 0) n->neg = !neg1 != !neg2;
1634 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1639 b->len = n->len - idx;
1641 a->rdx = b->rdx = 0;
1643 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1644 memcpy(a->num, n->num, idx * sizeof(BcDig));
1655 static BcStatus bc_num_shift(BcNum *n, size_t places)
1657 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1658 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1660 if (n->rdx >= places)
1663 bc_num_extend(n, places - n->rdx);
1669 return BC_STATUS_SUCCESS;
1672 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1681 return bc_num_div(&one, a, b, scale);
1684 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1686 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1687 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1690 // Because this function doesn't need to use scale (per the bc spec),
1691 // I am hijacking it to say whether it's doing an add or a subtract.
1695 if (sub && c->len) c->neg = !c->neg;
1696 return BC_STATUS_SUCCESS;
1698 else if (b->len == 0) {
1700 return BC_STATUS_SUCCESS;
1704 c->rdx = BC_MAX(a->rdx, b->rdx);
1705 min_rdx = BC_MIN(a->rdx, b->rdx);
1708 if (a->rdx > b->rdx) {
1709 diff = a->rdx - b->rdx;
1711 ptr_a = a->num + diff;
1715 diff = b->rdx - a->rdx;
1718 ptr_b = b->num + diff;
1721 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1724 a_int = BC_NUM_INT(a);
1725 b_int = BC_NUM_INT(b);
1727 if (a_int > b_int) {
1738 for (carry = 0, i = 0; !bcg.signe && i < min_rdx + min_int; ++i, ++c->len) {
1739 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1741 ptr_c[i] = (BcDig)(in % 10);
1744 for (; !bcg.signe && i < max + min_rdx; ++i, ++c->len) {
1745 in = ((int) ptr[i]) + carry;
1747 ptr_c[i] = (BcDig)(in % 10);
1750 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1752 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1755 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1759 BcNum *minuend, *subtrahend;
1761 bool aneg, bneg, neg;
1763 // Because this function doesn't need to use scale (per the bc spec),
1764 // I am hijacking it to say whether it's doing an add or a subtract.
1768 if (sub && c->len) c->neg = !c->neg;
1769 return BC_STATUS_SUCCESS;
1771 else if (b->len == 0) {
1773 return BC_STATUS_SUCCESS;
1778 a->neg = b->neg = false;
1780 cmp = bc_num_cmp(a, b);
1786 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1787 return BC_STATUS_SUCCESS;
1796 if (sub) neg = !neg;
1801 bc_num_copy(c, minuend);
1804 if (c->rdx < subtrahend->rdx) {
1805 bc_num_extend(c, subtrahend->rdx - c->rdx);
1809 start = c->rdx - subtrahend->rdx;
1811 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1818 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1823 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1824 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1825 bool aone = BC_NUM_ONE(a);
1827 if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
1828 if (a->len == 0 || b->len == 0) {
1830 return BC_STATUS_SUCCESS;
1832 else if (aone || BC_NUM_ONE(b)) {
1833 bc_num_copy(c, aone ? b : a);
1834 return BC_STATUS_SUCCESS;
1837 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1838 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1840 bc_num_expand(c, a->len + b->len + 1);
1842 memset(c->num, 0, sizeof(BcDig) * c->cap);
1843 c->len = carry = len = 0;
1845 for (i = 0; !bcg.signe && i < b->len; ++i) {
1847 for (j = 0; !bcg.signe && j < a->len; ++j) {
1848 int in = (int) c->num[i + j];
1849 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1851 c->num[i + j] = (BcDig)(in % 10);
1854 c->num[i + j] += (BcDig) carry;
1855 len = BC_MAX(len, i + j + !!carry);
1861 return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
1864 bc_num_init(&l1, max);
1865 bc_num_init(&h1, max);
1866 bc_num_init(&l2, max);
1867 bc_num_init(&h2, max);
1868 bc_num_init(&m1, max);
1869 bc_num_init(&m2, max);
1870 bc_num_init(&z0, max);
1871 bc_num_init(&z1, max);
1872 bc_num_init(&z2, max);
1873 bc_num_init(&temp, max + max);
1875 bc_num_split(a, max2, &l1, &h1);
1876 bc_num_split(b, max2, &l2, &h2);
1878 s = bc_num_add(&h1, &l1, &m1, 0);
1880 s = bc_num_add(&h2, &l2, &m2, 0);
1883 s = bc_num_k(&h1, &h2, &z0);
1885 s = bc_num_k(&m1, &m2, &z1);
1887 s = bc_num_k(&l1, &l2, &z2);
1890 s = bc_num_sub(&z1, &z0, &temp, 0);
1892 s = bc_num_sub(&temp, &z2, &z1, 0);
1895 s = bc_num_shift(&z0, max2 * 2);
1897 s = bc_num_shift(&z1, max2);
1899 s = bc_num_add(&z0, &z1, &temp, 0);
1901 s = bc_num_add(&temp, &z2, c, 0);
1917 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1921 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1923 scale = BC_MAX(scale, a->rdx);
1924 scale = BC_MAX(scale, b->rdx);
1925 scale = BC_MIN(a->rdx + b->rdx, scale);
1926 maxrdx = BC_MAX(maxrdx, scale);
1928 bc_num_init(&cpa, a->len);
1929 bc_num_init(&cpb, b->len);
1931 bc_num_copy(&cpa, a);
1932 bc_num_copy(&cpb, b);
1933 cpa.neg = cpb.neg = false;
1935 s = bc_num_shift(&cpa, maxrdx);
1937 s = bc_num_shift(&cpb, maxrdx);
1939 s = bc_num_k(&cpa, &cpb, c);
1943 bc_num_expand(c, c->len + maxrdx);
1945 if (c->len < maxrdx) {
1946 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1951 bc_num_retireMul(c, scale, a->neg, b->neg);
1959 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1961 BcStatus s = BC_STATUS_SUCCESS;
1968 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1969 else if (a->len == 0) {
1970 bc_num_setToZero(c, scale);
1971 return BC_STATUS_SUCCESS;
1973 else if (BC_NUM_ONE(b)) {
1975 bc_num_retireMul(c, scale, a->neg, b->neg);
1976 return BC_STATUS_SUCCESS;
1979 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1980 bc_num_copy(&cp, a);
1984 bc_num_expand(&cp, len + 2);
1985 bc_num_extend(&cp, len - cp.len);
1988 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1990 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1992 if (b->rdx == b->len) {
1993 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1997 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1999 // We want an extra zero in front to make things simpler.
2000 cp.num[cp.len++] = 0;
2003 bc_num_expand(c, cp.len);
2006 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
2011 for (i = end - 1; !bcg.signe && !s && i < end; --i) {
2013 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
2014 s = bc_num_subArrays(n, p, len);
2018 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
2024 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
2025 BcNum *restrict d, size_t scale, size_t ts)
2031 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2034 bc_num_setToZero(d, ts);
2035 return BC_STATUS_SUCCESS;
2038 bc_num_init(&temp, d->cap);
2039 bc_num_d(a, b, c, scale);
2041 if (scale != 0) scale = ts;
2043 s = bc_num_m(c, b, &temp, scale);
2045 s = bc_num_sub(a, &temp, d, scale);
2048 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2051 bc_num_retireMul(d, ts, a->neg, b->neg);
2059 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2063 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2065 bc_num_init(&c1, len);
2066 s = bc_num_r(a, b, &c1, c, scale, ts);
2072 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2074 BcStatus s = BC_STATUS_SUCCESS;
2077 size_t i, powrdx, resrdx;
2080 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2084 return BC_STATUS_SUCCESS;
2086 else if (a->len == 0) {
2087 bc_num_setToZero(c, scale);
2088 return BC_STATUS_SUCCESS;
2090 else if (BC_NUM_ONE(b)) {
2094 s = bc_num_inv(a, c, scale);
2101 s = bc_num_ulong(b, &pow);
2104 bc_num_init(©, a->len);
2105 bc_num_copy(©, a);
2107 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2111 for (powrdx = a->rdx; !bcg.signe && !(pow & 1); pow >>= 1) {
2113 s = bc_num_mul(©, ©, ©, powrdx);
2118 s = BC_STATUS_EXEC_SIGNAL;
2122 bc_num_copy(c, ©);
2124 for (resrdx = powrdx, pow >>= 1; !bcg.signe && pow != 0; pow >>= 1) {
2127 s = bc_num_mul(©, ©, ©, powrdx);
2132 s = bc_num_mul(c, ©, c, resrdx);
2138 s = bc_num_inv(c, c, scale);
2143 s = BC_STATUS_EXEC_SIGNAL;
2147 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2149 // We can't use bc_num_clean() here.
2150 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2151 if (zero) bc_num_setToZero(c, scale);
2158 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2159 BcNumBinaryOp op, size_t req)
2162 BcNum num2, *ptr_a, *ptr_b;
2167 memcpy(ptr_a, c, sizeof(BcNum));
2176 memcpy(ptr_b, c, sizeof(BcNum));
2184 bc_num_init(c, req);
2186 bc_num_expand(c, req);
2188 s = op(ptr_a, ptr_b, c, scale);
2190 if (init) bc_num_free(&num2);
2195 static bool bc_num_strValid(const char *val, size_t base)
2198 bool small, radix = false;
2199 size_t i, len = strlen(val);
2201 if (!len) return true;
2204 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2206 for (i = 0; i < len; ++i) {
2212 if (radix) return false;
2218 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2225 static void bc_num_parseDecimal(BcNum *n, const char *val)
2231 for (i = 0; val[i] == '0'; ++i);
2238 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2239 bc_num_expand(n, len);
2242 ptr = strchr(val, '.');
2244 // Explicitly test for NULL here to produce either a 0 or 1.
2245 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2248 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2249 n->num[n->len] = val[i] - '0';
2253 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2256 BcNum temp, mult, result;
2260 size_t i, digits, len = strlen(val);
2264 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2267 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2268 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2270 for (i = 0; i < len; ++i) {
2273 if (c == '.') break;
2275 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2277 s = bc_num_mul(n, base, &mult, 0);
2278 if (s) goto int_err;
2279 s = bc_num_ulong2num(&temp, v);
2280 if (s) goto int_err;
2281 s = bc_num_add(&mult, &temp, n, 0);
2282 if (s) goto int_err;
2287 if (c == 0) goto int_err;
2290 bc_num_init(&result, base->len);
2291 bc_num_zero(&result);
2294 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2299 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2301 s = bc_num_mul(&result, base, &result, 0);
2303 s = bc_num_ulong2num(&temp, v);
2305 s = bc_num_add(&result, &temp, &result, 0);
2307 s = bc_num_mul(&mult, base, &mult, 0);
2311 s = bc_num_div(&result, &mult, &result, digits);
2313 s = bc_num_add(n, &result, n, digits);
2317 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2323 bc_num_free(&result);
2329 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2331 if (*nchars == line_len - 1) {
2332 bc_vm_putchar('\\');
2333 bc_vm_putchar('\n');
2339 static void bc_num_printChar(size_t num, size_t width, bool radix,
2340 size_t *nchars, size_t line_len)
2342 (void) radix, (void) line_len;
2343 bc_vm_putchar((char) num);
2344 *nchars = *nchars + width;
2348 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2349 size_t *nchars, size_t line_len)
2351 size_t exp, pow, div;
2353 bc_num_printNewline(nchars, line_len);
2354 bc_vm_putchar(radix ? '.' : ' ');
2357 bc_num_printNewline(nchars, line_len);
2358 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10);
2360 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2361 bc_num_printNewline(nchars, line_len);
2364 bc_vm_putchar(((char) div) + '0');
2368 static void bc_num_printHex(size_t num, size_t width, bool radix,
2369 size_t *nchars, size_t line_len)
2372 bc_num_printNewline(nchars, line_len);
2377 bc_num_printNewline(nchars, line_len);
2378 bc_vm_putchar(bc_num_hex_digits[num]);
2379 *nchars = *nchars + width;
2382 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2384 size_t i, rdx = n->rdx - 1;
2386 if (n->neg) bc_vm_putchar('-');
2387 (*nchars) += n->neg;
2389 for (i = n->len - 1; i < n->len; --i)
2390 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2393 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2394 size_t *nchars, size_t len, BcNumDigitOp print)
2398 BcNum intp, fracp, digit, frac_len;
2399 unsigned long dig, *ptr;
2404 print(0, width, false, nchars, len);
2405 return BC_STATUS_SUCCESS;
2408 bc_vec_init(&stack, sizeof(long), NULL);
2409 bc_num_init(&intp, n->len);
2410 bc_num_init(&fracp, n->rdx);
2411 bc_num_init(&digit, width);
2412 bc_num_init(&frac_len, BC_NUM_INT(n));
2413 bc_num_copy(&intp, n);
2414 bc_num_one(&frac_len);
2416 bc_num_truncate(&intp, intp.rdx);
2417 s = bc_num_sub(n, &intp, &fracp, 0);
2420 while (intp.len != 0) {
2421 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2423 s = bc_num_ulong(&digit, &dig);
2425 bc_vec_push(&stack, &dig);
2428 for (i = 0; i < stack.len; ++i) {
2429 ptr = bc_vec_item_rev(&stack, i);
2430 print(*ptr, width, false, nchars, len);
2433 if (!n->rdx) goto err;
2435 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2436 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2438 s = bc_num_ulong(&fracp, &dig);
2440 s = bc_num_ulong2num(&intp, dig);
2442 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2444 print(dig, width, radix, nchars, len);
2445 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2450 bc_num_free(&frac_len);
2451 bc_num_free(&digit);
2452 bc_num_free(&fracp);
2454 bc_vec_free(&stack);
2458 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2459 size_t *nchars, size_t line_len)
2466 if (neg) bc_vm_putchar('-');
2471 if (base_t <= BC_NUM_MAX_IBASE) {
2473 print = bc_num_printHex;
2476 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2477 print = bc_num_printDigits;
2480 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2487 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2489 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2493 static void bc_num_init(BcNum *n, size_t req)
2495 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2496 memset(n, 0, sizeof(BcNum));
2497 n->num = xmalloc(req);
2501 static void bc_num_expand(BcNum *n, size_t req)
2503 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2505 n->num = xrealloc(n->num, req);
2510 static void bc_num_free(void *num)
2512 free(((BcNum *) num)->num);
2515 static void bc_num_copy(BcNum *d, BcNum *s)
2518 bc_num_expand(d, s->cap);
2522 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2526 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2529 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2532 bc_num_parseDecimal(n, val);
2534 bc_num_parseBase(n, val, base);
2536 return BC_STATUS_SUCCESS;
2539 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2540 size_t *nchars, size_t line_len)
2542 BcStatus s = BC_STATUS_SUCCESS;
2544 bc_num_printNewline(nchars, line_len);
2550 else if (base_t == 10)
2551 bc_num_printDecimal(n, nchars, line_len);
2553 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2556 bc_vm_putchar('\n');
2563 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2568 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2570 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2572 unsigned long prev = *result, powprev = pow;
2574 *result += ((unsigned long) n->num[i]) * pow;
2577 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2580 return BC_STATUS_SUCCESS;
2583 static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val)
2591 if (val == 0) return BC_STATUS_SUCCESS;
2593 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2594 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2596 return BC_STATUS_SUCCESS;
2599 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2601 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2603 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2606 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2608 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2610 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2613 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2615 size_t req = BC_NUM_MREQ(a, b, scale);
2616 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2619 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2621 size_t req = BC_NUM_MREQ(a, b, scale);
2622 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2625 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2627 size_t req = BC_NUM_MREQ(a, b, scale);
2628 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2631 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2633 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2636 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2639 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2640 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2641 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2643 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2644 bc_num_expand(b, req);
2647 bc_num_setToZero(b, scale);
2648 return BC_STATUS_SUCCESS;
2651 return BC_STATUS_MATH_NEGATIVE;
2652 else if (BC_NUM_ONE(a)) {
2654 bc_num_extend(b, scale);
2655 return BC_STATUS_SUCCESS;
2658 scale = BC_MAX(scale, a->rdx) + 1;
2659 len = a->len + scale;
2661 bc_num_init(&num1, len);
2662 bc_num_init(&num2, len);
2663 bc_num_init(&half, BC_NUM_DEF_SIZE);
2669 bc_num_init(&f, len);
2670 bc_num_init(&fprime, len);
2676 pow = BC_NUM_INT(a);
2685 pow -= 2 - (pow & 1);
2687 bc_num_extend(x0, pow);
2689 // Make sure to move the radix back.
2693 x0->rdx = digs = digs1 = 0;
2695 len = BC_NUM_INT(x0) + resrdx - 1;
2697 while (!bcg.signe && (cmp != 0 || digs < len)) {
2699 s = bc_num_div(a, x0, &f, resrdx);
2701 s = bc_num_add(x0, &f, &fprime, resrdx);
2703 s = bc_num_mul(&fprime, &half, x1, resrdx);
2706 cmp = bc_num_cmp(x1, x0);
2707 digs = x1->len - (unsigned long long) llabs(cmp);
2709 if (cmp == cmp2 && digs == digs1)
2714 resrdx += times > 4;
2726 s = BC_STATUS_EXEC_SIGNAL;
2732 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2735 bc_num_free(&fprime);
2743 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2749 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2752 memcpy(&num2, c, sizeof(BcNum));
2754 bc_num_init(c, len);
2759 bc_num_expand(c, len);
2762 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2764 if (init) bc_num_free(&num2);
2770 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2773 BcNum base, exp, two, temp;
2775 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2776 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2777 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2779 bc_num_expand(d, c->len);
2780 bc_num_init(&base, c->len);
2781 bc_num_init(&exp, b->len);
2782 bc_num_init(&two, BC_NUM_DEF_SIZE);
2783 bc_num_init(&temp, b->len);
2789 s = bc_num_rem(a, c, &base, 0);
2791 bc_num_copy(&exp, b);
2793 while (exp.len != 0) {
2795 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2798 if (BC_NUM_ONE(&temp)) {
2799 s = bc_num_mul(d, &base, &temp, 0);
2801 s = bc_num_rem(&temp, c, d, 0);
2805 s = bc_num_mul(&base, &base, &temp, 0);
2807 s = bc_num_rem(&temp, c, &base, 0);
2820 static int bc_id_cmp(const void *e1, const void *e2)
2822 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2825 static void bc_id_free(void *id)
2827 free(((BcId *) id)->name);
2830 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2835 for (i = 0; i < f->autos.len; ++i) {
2836 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2837 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2843 bc_vec_push(&f->autos, &a);
2845 return BC_STATUS_SUCCESS;
2848 static void bc_func_init(BcFunc *f)
2850 bc_vec_init(&f->code, sizeof(char), NULL);
2851 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2852 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2856 static void bc_func_free(void *func)
2858 BcFunc *f = (BcFunc *) func;
2859 bc_vec_free(&f->code);
2860 bc_vec_free(&f->autos);
2861 bc_vec_free(&f->labels);
2864 static void bc_array_init(BcVec *a, bool nums)
2867 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2869 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2870 bc_array_expand(a, 1);
2873 static void bc_array_copy(BcVec *d, const BcVec *s)
2877 bc_vec_npop(d, d->len);
2878 bc_vec_expand(d, s->cap);
2881 for (i = 0; i < s->len; ++i) {
2882 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2883 bc_num_init(dnum, snum->len);
2884 bc_num_copy(dnum, snum);
2888 static void bc_array_expand(BcVec *a, size_t len)
2892 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2893 while (len > a->len) {
2894 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2895 bc_vec_push(a, &data.n);
2899 while (len > a->len) {
2900 bc_array_init(&data.v, true);
2901 bc_vec_push(a, &data.v);
2906 static void bc_string_free(void *string)
2908 free(*((char **) string));
2912 static void bc_result_copy(BcResult *d, BcResult *src)
2918 case BC_RESULT_TEMP:
2919 case BC_RESULT_IBASE:
2920 case BC_RESULT_SCALE:
2921 case BC_RESULT_OBASE:
2923 bc_num_init(&d->d.n, src->d.n.len);
2924 bc_num_copy(&d->d.n, &src->d.n);
2929 case BC_RESULT_ARRAY:
2930 case BC_RESULT_ARRAY_ELEM:
2932 d->d.id.name = xstrdup(src->d.id.name);
2936 case BC_RESULT_CONSTANT:
2937 case BC_RESULT_LAST:
2941 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2948 static void bc_result_free(void *result)
2950 BcResult *r = (BcResult *) result;
2954 case BC_RESULT_TEMP:
2955 case BC_RESULT_IBASE:
2956 case BC_RESULT_SCALE:
2957 case BC_RESULT_OBASE:
2959 bc_num_free(&r->d.n);
2964 case BC_RESULT_ARRAY:
2965 case BC_RESULT_ARRAY_ELEM:
2979 static void bc_lex_lineComment(BcLex *l)
2981 l->t.t = BC_LEX_WHITESPACE;
2982 while (l->i < l->len && l->buf[l->i++] != '\n');
2986 static void bc_lex_whitespace(BcLex *l)
2989 l->t.t = BC_LEX_WHITESPACE;
2990 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2993 static BcStatus bc_lex_number(BcLex *l, char start)
2995 const char *buf = l->buf + l->i;
2996 size_t len, hits = 0, bslashes = 0, i = 0, j;
2998 bool last_pt, pt = start == '.';
3001 l->t.t = BC_LEX_NUMBER;
3003 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
3004 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
3018 len = i + 1 * !last_pt - bslashes * 2;
3019 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
3021 bc_vec_npop(&l->t.v, l->t.v.len);
3022 bc_vec_expand(&l->t.v, len + 1);
3023 bc_vec_push(&l->t.v, &start);
3025 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
3029 // If we have hit a backslash, skip it. We don't have
3030 // to check for a newline because it's guaranteed.
3031 if (hits < bslashes && c == '\\') {
3037 bc_vec_push(&l->t.v, &c);
3040 bc_vec_pushByte(&l->t.v, '\0');
3043 return BC_STATUS_SUCCESS;
3046 static BcStatus bc_lex_name(BcLex *l)
3049 const char *buf = l->buf + l->i - 1;
3052 l->t.t = BC_LEX_NAME;
3054 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3056 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3057 bc_vec_string(&l->t.v, i, buf);
3059 // Increment the index. We minus 1 because it has already been incremented.
3062 return BC_STATUS_SUCCESS;
3065 static void bc_lex_init(BcLex *l, BcLexNext next)
3068 bc_vec_init(&l->t.v, sizeof(char), NULL);
3071 static void bc_lex_free(BcLex *l)
3073 bc_vec_free(&l->t.v);
3076 static void bc_lex_file(BcLex *l, const char *file)
3083 static BcStatus bc_lex_next(BcLex *l)
3088 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3090 l->line += l->newline;
3091 l->t.t = BC_LEX_EOF;
3093 l->newline = (l->i == l->len);
3094 if (l->newline) return BC_STATUS_SUCCESS;
3096 // Loop until failure or we don't have whitespace. This
3097 // is so the parser doesn't get inundated with whitespace.
3100 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3105 static BcStatus bc_lex_text(BcLex *l, const char *text)
3109 l->len = strlen(text);
3110 l->t.t = l->t.last = BC_LEX_INVALID;
3111 return bc_lex_next(l);
3115 static BcStatus bc_lex_identifier(BcLex *l)
3119 const char *buf = l->buf + l->i - 1;
3121 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3123 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3125 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3127 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3129 if (!bc_lex_kws[i].posix) {
3130 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3131 bc_lex_kws[i].name);
3135 // We minus 1 because the index has already been incremented.
3137 return BC_STATUS_SUCCESS;
3144 if (l->t.v.len - 1 > 1)
3145 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3150 static BcStatus bc_lex_string(BcLex *l)
3152 size_t len, nls = 0, i = l->i;
3155 l->t.t = BC_LEX_STR;
3157 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3161 return BC_STATUS_LEX_NO_STRING_END;
3165 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3166 bc_vec_string(&l->t.v, len, l->buf + l->i);
3171 return BC_STATUS_SUCCESS;
3174 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3176 if (l->buf[l->i] == '=') {
3184 static BcStatus bc_lex_comment(BcLex *l)
3187 const char *buf = l->buf;
3191 l->t.t = BC_LEX_WHITESPACE;
3193 for (i = ++l->i; !end; i += !end) {
3195 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3197 if (c == 0 || buf[i + 1] == '\0') {
3199 return BC_STATUS_LEX_NO_COMMENT_END;
3202 end = buf[i + 1] == '/';
3208 return BC_STATUS_SUCCESS;
3211 static BcStatus bc_lex_token(BcLex *l)
3213 BcStatus s = BC_STATUS_SUCCESS;
3214 char c = l->buf[l->i++], c2;
3216 // This is the workhorse of the lexer.
3223 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3233 bc_lex_whitespace(l);
3239 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3241 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3242 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3251 s = bc_lex_string(l);
3257 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3260 bc_lex_lineComment(l);
3267 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3276 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3280 l->t.t = BC_LEX_OP_BOOL_AND;
3283 l->t.t = BC_LEX_INVALID;
3284 s = BC_STATUS_LEX_BAD_CHAR;
3293 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3299 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3308 l->t.t = BC_LEX_OP_INC;
3311 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3317 l->t.t = BC_LEX_COMMA;
3326 l->t.t = BC_LEX_OP_DEC;
3329 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3335 if (isdigit(l->buf[l->i]))
3336 s = bc_lex_number(l, c);
3338 l->t.t = BC_LEX_KEY_LAST;
3339 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3348 s = bc_lex_comment(l);
3350 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3371 s = bc_lex_number(l, c);
3377 l->t.t = BC_LEX_SCOLON;
3383 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3389 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3395 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3402 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3408 if (l->buf[l->i] == '\n') {
3409 l->t.t = BC_LEX_WHITESPACE;
3413 s = BC_STATUS_LEX_BAD_CHAR;
3419 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3450 s = bc_lex_identifier(l);
3457 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3467 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3471 l->t.t = BC_LEX_OP_BOOL_OR;
3474 l->t.t = BC_LEX_INVALID;
3475 s = BC_STATUS_LEX_BAD_CHAR;
3483 l->t.t = BC_LEX_INVALID;
3484 s = BC_STATUS_LEX_BAD_CHAR;
3494 static BcStatus dc_lex_register(BcLex *l)
3496 BcStatus s = BC_STATUS_SUCCESS;
3498 if (isspace(l->buf[l->i - 1])) {
3499 bc_lex_whitespace(l);
3502 s = BC_STATUS_LEX_EXTENDED_REG;
3507 bc_vec_npop(&l->t.v, l->t.v.len);
3508 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3509 bc_vec_pushByte(&l->t.v, '\0');
3510 l->t.t = BC_LEX_NAME;
3516 static BcStatus dc_lex_string(BcLex *l)
3518 size_t depth = 1, nls = 0, i = l->i;
3521 l->t.t = BC_LEX_STR;
3522 bc_vec_npop(&l->t.v, l->t.v.len);
3524 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3526 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3527 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3530 if (depth) bc_vec_push(&l->t.v, &c);
3535 return BC_STATUS_LEX_NO_STRING_END;
3538 bc_vec_pushByte(&l->t.v, '\0');
3539 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3544 return BC_STATUS_SUCCESS;
3547 static BcStatus dc_lex_token(BcLex *l)
3549 BcStatus s = BC_STATUS_SUCCESS;
3550 char c = l->buf[l->i++], c2;
3553 for (i = 0; i < dc_lex_regs_len; ++i) {
3554 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3557 if (c >= '%' && c <= '~' &&
3558 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3563 // This is the workhorse of the lexer.
3568 l->t.t = BC_LEX_EOF;
3579 l->newline = (c == '\n');
3580 bc_lex_whitespace(l);
3589 l->t.t = BC_LEX_OP_REL_NE;
3591 l->t.t = BC_LEX_OP_REL_LE;
3593 l->t.t = BC_LEX_OP_REL_GE;
3595 return BC_STATUS_LEX_BAD_CHAR;
3603 bc_lex_lineComment(l);
3609 if (isdigit(l->buf[l->i]))
3610 s = bc_lex_number(l, c);
3612 s = BC_STATUS_LEX_BAD_CHAR;
3633 s = bc_lex_number(l, c);
3639 s = dc_lex_string(l);
3645 l->t.t = BC_LEX_INVALID;
3646 s = BC_STATUS_LEX_BAD_CHAR;
3655 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3657 bc_program_addFunc(p->prog, name, idx);
3658 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3661 static void bc_parse_pushName(BcParse *p, char *name)
3663 size_t i = 0, len = strlen(name);
3665 for (; i < len; ++i) bc_parse_push(p, name[i]);
3666 bc_parse_push(p, BC_PARSE_STREND);
3671 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3673 unsigned char amt, i, nums[sizeof(size_t)];
3675 for (amt = 0; idx; ++amt) {
3676 nums[amt] = (char) idx;
3677 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3680 bc_parse_push(p, amt);
3681 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3684 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3686 char *num = xstrdup(p->l.t.v.v);
3687 size_t idx = p->prog->consts.len;
3689 bc_vec_push(&p->prog->consts, &num);
3691 bc_parse_push(p, BC_INST_NUM);
3692 bc_parse_pushIndex(p, idx);
3695 (*prev) = BC_INST_NUM;
3698 static BcStatus bc_parse_text(BcParse *p, const char *text)
3702 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3704 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3705 p->l.t.t = BC_LEX_INVALID;
3708 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3711 return bc_lex_text(&p->l, text);
3714 static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3716 if (p->fidx != BC_PROG_MAIN) {
3718 p->func->nparams = 0;
3719 bc_vec_npop(&p->func->code, p->func->code.len);
3720 bc_vec_npop(&p->func->autos, p->func->autos.len);
3721 bc_vec_npop(&p->func->labels, p->func->labels.len);
3723 bc_parse_updateFunc(p, BC_PROG_MAIN);
3727 p->l.t.t = BC_LEX_EOF;
3728 p->auto_part = (p->nbraces = 0);
3730 bc_vec_npop(&p->flags, p->flags.len - 1);
3731 bc_vec_npop(&p->exits, p->exits.len);
3732 bc_vec_npop(&p->conds, p->conds.len);
3733 bc_vec_npop(&p->ops, p->ops.len);
3735 return bc_program_reset(p->prog, s);
3738 static void bc_parse_free(BcParse *p)
3740 bc_vec_free(&p->flags);
3741 bc_vec_free(&p->exits);
3742 bc_vec_free(&p->conds);
3743 bc_vec_free(&p->ops);
3747 static void bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
3748 BcParseParse parse, BcLexNext next)
3750 memset(p, 0, sizeof(BcParse));
3752 bc_lex_init(&p->l, next);
3753 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3754 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3755 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3756 bc_vec_pushByte(&p->flags, 0);
3757 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3761 p->auto_part = (p->nbraces = 0);
3762 bc_parse_updateFunc(p, func);
3766 static BcStatus bc_parse_else(BcParse *p);
3767 static BcStatus bc_parse_stmt(BcParse *p);
3769 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3770 size_t *nexprs, bool next)
3772 BcStatus s = BC_STATUS_SUCCESS;
3774 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3775 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3777 while (p->ops.len > start) {
3779 t = BC_PARSE_TOP_OP(p);
3780 if (t == BC_LEX_LPAREN) break;
3782 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3783 if (l >= r && (l != r || !left)) break;
3785 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3786 bc_vec_pop(&p->ops);
3787 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3790 bc_vec_push(&p->ops, &type);
3791 if (next) s = bc_lex_next(&p->l);
3796 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3800 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3801 top = BC_PARSE_TOP_OP(p);
3803 while (top != BC_LEX_LPAREN) {
3805 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3807 bc_vec_pop(&p->ops);
3808 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3810 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3811 top = BC_PARSE_TOP_OP(p);
3814 bc_vec_pop(&p->ops);
3816 return bc_lex_next(&p->l);
3819 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3825 s = bc_lex_next(&p->l);
3828 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3830 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3831 s = bc_parse_expr(p, flags, bc_parse_next_param);
3834 comma = p->l.t.t == BC_LEX_COMMA;
3836 s = bc_lex_next(&p->l);
3841 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3842 bc_parse_push(p, BC_INST_CALL);
3843 bc_parse_pushIndex(p, nparams);
3845 return BC_STATUS_SUCCESS;
3848 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3851 BcId entry, *entry_ptr;
3856 s = bc_parse_params(p, flags);
3859 if (p->l.t.t != BC_LEX_RPAREN) {
3860 s = BC_STATUS_PARSE_BAD_TOKEN;
3864 idx = bc_map_index(&p->prog->fn_map, &entry);
3866 if (idx == BC_VEC_INVALID_IDX) {
3867 name = xstrdup(entry.name);
3868 bc_parse_addFunc(p, name, &idx);
3869 idx = bc_map_index(&p->prog->fn_map, &entry);
3875 entry_ptr = bc_vec_item(&p->prog->fn_map, idx);
3876 bc_parse_pushIndex(p, entry_ptr->idx);
3878 return bc_lex_next(&p->l);
3885 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3890 name = xstrdup(p->l.t.v.v);
3891 s = bc_lex_next(&p->l);
3894 if (p->l.t.t == BC_LEX_LBRACKET) {
3896 s = bc_lex_next(&p->l);
3899 if (p->l.t.t == BC_LEX_RBRACKET) {
3901 if (!(flags & BC_PARSE_ARRAY)) {
3902 s = BC_STATUS_PARSE_BAD_EXP;
3906 *type = BC_INST_ARRAY;
3910 *type = BC_INST_ARRAY_ELEM;
3912 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3913 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3917 s = bc_lex_next(&p->l);
3919 bc_parse_push(p, *type);
3920 bc_parse_pushName(p, name);
3922 else if (p->l.t.t == BC_LEX_LPAREN) {
3924 if (flags & BC_PARSE_NOCALL) {
3925 s = BC_STATUS_PARSE_BAD_TOKEN;
3929 *type = BC_INST_CALL;
3930 s = bc_parse_call(p, name, flags);
3933 *type = BC_INST_VAR;
3934 bc_parse_push(p, BC_INST_VAR);
3935 bc_parse_pushName(p, name);
3945 static BcStatus bc_parse_read(BcParse *p)
3949 s = bc_lex_next(&p->l);
3951 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3953 s = bc_lex_next(&p->l);
3955 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3957 bc_parse_push(p, BC_INST_READ);
3959 return bc_lex_next(&p->l);
3962 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3967 s = bc_lex_next(&p->l);
3969 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3971 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3973 s = bc_lex_next(&p->l);
3976 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3979 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3981 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3982 bc_parse_push(p, *prev);
3984 return bc_lex_next(&p->l);
3987 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3991 s = bc_lex_next(&p->l);
3994 if (p->l.t.t != BC_LEX_LPAREN) {
3995 *type = BC_INST_SCALE;
3996 bc_parse_push(p, BC_INST_SCALE);
3997 return BC_STATUS_SUCCESS;
4000 *type = BC_INST_SCALE_FUNC;
4001 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
4003 s = bc_lex_next(&p->l);
4006 s = bc_parse_expr(p, flags, bc_parse_next_rel);
4008 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4009 bc_parse_push(p, BC_INST_SCALE_FUNC);
4011 return bc_lex_next(&p->l);
4014 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
4015 size_t *nexprs, uint8_t flags)
4020 BcInst etype = *prev;
4022 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
4023 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
4024 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
4026 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
4027 bc_parse_push(p, inst);
4028 s = bc_lex_next(&p->l);
4032 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
4035 s = bc_lex_next(&p->l);
4039 // Because we parse the next part of the expression
4040 // right here, we need to increment this.
4041 *nexprs = *nexprs + 1;
4047 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4051 case BC_LEX_KEY_IBASE:
4052 case BC_LEX_KEY_LAST:
4053 case BC_LEX_KEY_OBASE:
4055 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4056 s = bc_lex_next(&p->l);
4060 case BC_LEX_KEY_SCALE:
4062 s = bc_lex_next(&p->l);
4064 if (p->l.t.t == BC_LEX_LPAREN)
4065 s = BC_STATUS_PARSE_BAD_TOKEN;
4067 bc_parse_push(p, BC_INST_SCALE);
4073 s = BC_STATUS_PARSE_BAD_TOKEN;
4078 if (!s) bc_parse_push(p, inst);
4084 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4085 bool rparen, size_t *nexprs)
4089 BcInst etype = *prev;
4091 s = bc_lex_next(&p->l);
4094 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4095 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4098 *prev = BC_PARSE_TOKEN_INST(type);
4100 // We can just push onto the op stack because this is the largest
4101 // precedence operator that gets pushed. Inc/dec does not.
4102 if (type != BC_LEX_OP_MINUS)
4103 bc_vec_push(&p->ops, &type);
4105 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4110 static BcStatus bc_parse_string(BcParse *p, char inst)
4112 char *str = xstrdup(p->l.t.v.v);
4114 bc_parse_push(p, BC_INST_STR);
4115 bc_parse_pushIndex(p, p->prog->strs.len);
4116 bc_vec_push(&p->prog->strs, &str);
4117 bc_parse_push(p, inst);
4119 return bc_lex_next(&p->l);
4122 static BcStatus bc_parse_print(BcParse *p)
4128 s = bc_lex_next(&p->l);
4133 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4134 return BC_STATUS_PARSE_BAD_PRINT;
4136 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4138 if (type == BC_LEX_STR)
4139 s = bc_parse_string(p, BC_INST_PRINT_POP);
4141 s = bc_parse_expr(p, 0, bc_parse_next_print);
4143 bc_parse_push(p, BC_INST_PRINT_POP);
4148 comma = p->l.t.t == BC_LEX_COMMA;
4149 if (comma) s = bc_lex_next(&p->l);
4154 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4156 return bc_lex_next(&p->l);
4159 static BcStatus bc_parse_return(BcParse *p)
4165 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4167 s = bc_lex_next(&p->l);
4171 paren = t == BC_LEX_LPAREN;
4173 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4174 bc_parse_push(p, BC_INST_RET0);
4177 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4178 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4180 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4181 bc_parse_push(p, BC_INST_RET0);
4182 s = bc_lex_next(&p->l);
4186 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4187 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4191 bc_parse_push(p, BC_INST_RET);
4197 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4199 BcStatus s = BC_STATUS_SUCCESS;
4201 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4202 return BC_STATUS_PARSE_BAD_TOKEN;
4206 if (p->l.t.t == BC_LEX_RBRACE) {
4207 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4209 s = bc_lex_next(&p->l);
4213 return BC_STATUS_PARSE_BAD_TOKEN;
4216 if (BC_PARSE_IF(p)) {
4220 while (p->l.t.t == BC_LEX_NLINE) {
4221 s = bc_lex_next(&p->l);
4225 bc_vec_pop(&p->flags);
4227 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4228 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4230 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4232 else if (BC_PARSE_ELSE(p)) {
4237 bc_vec_pop(&p->flags);
4239 ip = bc_vec_top(&p->exits);
4240 label = bc_vec_item(&p->func->labels, ip->idx);
4241 *label = p->func->code.len;
4243 bc_vec_pop(&p->exits);
4245 else if (BC_PARSE_FUNC_INNER(p)) {
4246 bc_parse_push(p, BC_INST_RET0);
4247 bc_parse_updateFunc(p, BC_PROG_MAIN);
4248 bc_vec_pop(&p->flags);
4252 BcInstPtr *ip = bc_vec_top(&p->exits);
4253 size_t *label = bc_vec_top(&p->conds);
4255 bc_parse_push(p, BC_INST_JUMP);
4256 bc_parse_pushIndex(p, *label);
4258 label = bc_vec_item(&p->func->labels, ip->idx);
4259 *label = p->func->code.len;
4261 bc_vec_pop(&p->flags);
4262 bc_vec_pop(&p->exits);
4263 bc_vec_pop(&p->conds);
4269 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4271 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4272 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4273 flags |= BC_PARSE_FLAG_BODY;
4274 bc_vec_push(&p->flags, &flags);
4277 static void bc_parse_noElse(BcParse *p)
4281 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4283 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4285 ip = bc_vec_top(&p->exits);
4286 label = bc_vec_item(&p->func->labels, ip->idx);
4287 *label = p->func->code.len;
4289 bc_vec_pop(&p->exits);
4292 static BcStatus bc_parse_if(BcParse *p)
4297 s = bc_lex_next(&p->l);
4299 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4301 s = bc_lex_next(&p->l);
4303 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4305 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4307 s = bc_lex_next(&p->l);
4309 bc_parse_push(p, BC_INST_JUMP_ZERO);
4311 ip.idx = p->func->labels.len;
4312 ip.func = ip.len = 0;
4314 bc_parse_pushIndex(p, ip.idx);
4315 bc_vec_push(&p->exits, &ip);
4316 bc_vec_push(&p->func->labels, &ip.idx);
4317 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4319 return BC_STATUS_SUCCESS;
4322 static BcStatus bc_parse_else(BcParse *p)
4326 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4328 ip.idx = p->func->labels.len;
4329 ip.func = ip.len = 0;
4331 bc_parse_push(p, BC_INST_JUMP);
4332 bc_parse_pushIndex(p, ip.idx);
4336 bc_vec_push(&p->exits, &ip);
4337 bc_vec_push(&p->func->labels, &ip.idx);
4338 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4340 return bc_lex_next(&p->l);
4343 static BcStatus bc_parse_while(BcParse *p)
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 ip.idx = p->func->labels.len;
4356 bc_vec_push(&p->func->labels, &p->func->code.len);
4357 bc_vec_push(&p->conds, &ip.idx);
4359 ip.idx = p->func->labels.len;
4363 bc_vec_push(&p->exits, &ip);
4364 bc_vec_push(&p->func->labels, &ip.idx);
4366 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4368 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4369 s = bc_lex_next(&p->l);
4372 bc_parse_push(p, BC_INST_JUMP_ZERO);
4373 bc_parse_pushIndex(p, ip.idx);
4374 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4376 return BC_STATUS_SUCCESS;
4379 static BcStatus bc_parse_for(BcParse *p)
4383 size_t cond_idx, exit_idx, body_idx, update_idx;
4385 s = bc_lex_next(&p->l);
4387 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4388 s = bc_lex_next(&p->l);
4391 if (p->l.t.t != BC_LEX_SCOLON)
4392 s = bc_parse_expr(p, 0, bc_parse_next_for);
4394 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4397 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4398 s = bc_lex_next(&p->l);
4401 cond_idx = p->func->labels.len;
4402 update_idx = cond_idx + 1;
4403 body_idx = update_idx + 1;
4404 exit_idx = body_idx + 1;
4406 bc_vec_push(&p->func->labels, &p->func->code.len);
4408 if (p->l.t.t != BC_LEX_SCOLON)
4409 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4411 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4414 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4416 s = bc_lex_next(&p->l);
4419 bc_parse_push(p, BC_INST_JUMP_ZERO);
4420 bc_parse_pushIndex(p, exit_idx);
4421 bc_parse_push(p, BC_INST_JUMP);
4422 bc_parse_pushIndex(p, body_idx);
4424 ip.idx = p->func->labels.len;
4426 bc_vec_push(&p->conds, &update_idx);
4427 bc_vec_push(&p->func->labels, &p->func->code.len);
4429 if (p->l.t.t != BC_LEX_RPAREN)
4430 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4432 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4436 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4437 bc_parse_push(p, BC_INST_JUMP);
4438 bc_parse_pushIndex(p, cond_idx);
4439 bc_vec_push(&p->func->labels, &p->func->code.len);
4445 bc_vec_push(&p->exits, &ip);
4446 bc_vec_push(&p->func->labels, &ip.idx);
4448 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4450 return BC_STATUS_SUCCESS;
4453 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4459 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4461 if (type == BC_LEX_KEY_BREAK) {
4463 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4465 i = p->exits.len - 1;
4466 ip = bc_vec_item(&p->exits, i);
4468 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4469 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4474 i = *((size_t *) bc_vec_top(&p->conds));
4476 bc_parse_push(p, BC_INST_JUMP);
4477 bc_parse_pushIndex(p, i);
4479 s = bc_lex_next(&p->l);
4482 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4483 return BC_STATUS_PARSE_BAD_TOKEN;
4485 return bc_lex_next(&p->l);
4488 static BcStatus bc_parse_func(BcParse *p)
4491 bool var, comma = false;
4495 s = bc_lex_next(&p->l);
4497 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4499 name = xstrdup(p->l.t.v.v);
4500 bc_parse_addFunc(p, name, &p->fidx);
4502 s = bc_lex_next(&p->l);
4504 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4505 s = bc_lex_next(&p->l);
4508 while (p->l.t.t != BC_LEX_RPAREN) {
4510 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4514 name = xstrdup(p->l.t.v.v);
4515 s = bc_lex_next(&p->l);
4518 var = p->l.t.t != BC_LEX_LBRACKET;
4522 s = bc_lex_next(&p->l);
4525 if (p->l.t.t != BC_LEX_RBRACKET) {
4526 s = BC_STATUS_PARSE_BAD_FUNC;
4530 s = bc_lex_next(&p->l);
4534 comma = p->l.t.t == BC_LEX_COMMA;
4536 s = bc_lex_next(&p->l);
4540 s = bc_func_insert(p->func, name, var);
4544 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4546 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4547 bc_parse_startBody(p, flags);
4549 s = bc_lex_next(&p->l);
4552 if (p->l.t.t != BC_LEX_LBRACE)
4553 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4562 static BcStatus bc_parse_auto(BcParse *p)
4565 bool comma, var, one;
4568 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4569 s = bc_lex_next(&p->l);
4572 p->auto_part = comma = false;
4573 one = p->l.t.t == BC_LEX_NAME;
4575 while (p->l.t.t == BC_LEX_NAME) {
4577 name = xstrdup(p->l.t.v.v);
4578 s = bc_lex_next(&p->l);
4581 var = p->l.t.t != BC_LEX_LBRACKET;
4584 s = bc_lex_next(&p->l);
4587 if (p->l.t.t != BC_LEX_RBRACKET) {
4588 s = BC_STATUS_PARSE_BAD_FUNC;
4592 s = bc_lex_next(&p->l);
4596 comma = p->l.t.t == BC_LEX_COMMA;
4598 s = bc_lex_next(&p->l);
4602 s = bc_func_insert(p->func, name, var);
4606 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4607 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4609 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4610 return BC_STATUS_PARSE_BAD_TOKEN;
4612 return bc_lex_next(&p->l);
4619 static BcStatus bc_parse_body(BcParse *p, bool brace)
4621 BcStatus s = BC_STATUS_SUCCESS;
4622 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4624 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4626 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4628 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4629 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4631 if (!p->auto_part) {
4632 s = bc_parse_auto(p);
4636 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4639 s = bc_parse_stmt(p);
4640 if (!s && !brace) s = bc_parse_endBody(p, false);
4646 static BcStatus bc_parse_stmt(BcParse *p)
4648 BcStatus s = BC_STATUS_SUCCESS;
4654 return bc_lex_next(&p->l);
4657 case BC_LEX_KEY_ELSE:
4659 p->auto_part = false;
4665 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4668 s = bc_lex_next(&p->l);
4671 return bc_parse_body(p, true);
4674 case BC_LEX_KEY_AUTO:
4676 return bc_parse_auto(p);
4681 p->auto_part = false;
4683 if (BC_PARSE_IF_END(p)) {
4685 return BC_STATUS_SUCCESS;
4687 else if (BC_PARSE_BODY(p))
4688 return bc_parse_body(p, false);
4698 case BC_LEX_OP_MINUS:
4699 case BC_LEX_OP_BOOL_NOT:
4703 case BC_LEX_KEY_IBASE:
4704 case BC_LEX_KEY_LAST:
4705 case BC_LEX_KEY_LENGTH:
4706 case BC_LEX_KEY_OBASE:
4707 case BC_LEX_KEY_READ:
4708 case BC_LEX_KEY_SCALE:
4709 case BC_LEX_KEY_SQRT:
4711 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4715 case BC_LEX_KEY_ELSE:
4717 s = bc_parse_else(p);
4723 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4729 s = bc_parse_endBody(p, true);
4735 s = bc_parse_string(p, BC_INST_PRINT_STR);
4739 case BC_LEX_KEY_BREAK:
4740 case BC_LEX_KEY_CONTINUE:
4742 s = bc_parse_loopExit(p, p->l.t.t);
4746 case BC_LEX_KEY_FOR:
4748 s = bc_parse_for(p);
4752 case BC_LEX_KEY_HALT:
4754 bc_parse_push(p, BC_INST_HALT);
4755 s = bc_lex_next(&p->l);
4765 case BC_LEX_KEY_LIMITS:
4767 s = bc_lex_next(&p->l);
4769 s = BC_STATUS_LIMITS;
4773 case BC_LEX_KEY_PRINT:
4775 s = bc_parse_print(p);
4779 case BC_LEX_KEY_QUIT:
4781 // Quit is a compile-time command. We don't exit directly,
4782 // so the vm can clean up. Limits do the same thing.
4787 case BC_LEX_KEY_RETURN:
4789 s = bc_parse_return(p);
4793 case BC_LEX_KEY_WHILE:
4795 s = bc_parse_while(p);
4801 s = BC_STATUS_PARSE_BAD_TOKEN;
4809 static BcStatus bc_parse_parse(BcParse *p)
4813 if (p->l.t.t == BC_LEX_EOF)
4814 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4815 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4816 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4817 s = bc_parse_func(p);
4820 s = bc_parse_stmt(p);
4822 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || bcg.signe)
4823 s = bc_parse_reset(p, s);
4828 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4830 BcStatus s = BC_STATUS_SUCCESS;
4831 BcInst prev = BC_INST_PRINT;
4832 BcLexType top, t = p->l.t.t;
4833 size_t nexprs = 0, ops_bgn = p->ops.len;
4834 uint32_t i, nparens, nrelops;
4835 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4837 paren_first = p->l.t.t == BC_LEX_LPAREN;
4838 nparens = nrelops = 0;
4839 paren_expr = rprn = done = get_token = assign = false;
4842 for (; !bcg.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4848 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4849 rprn = get_token = bin_last = false;
4853 case BC_LEX_OP_MINUS:
4855 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4856 rprn = get_token = false;
4857 bin_last = prev == BC_INST_MINUS;
4861 case BC_LEX_OP_ASSIGN_POWER:
4862 case BC_LEX_OP_ASSIGN_MULTIPLY:
4863 case BC_LEX_OP_ASSIGN_DIVIDE:
4864 case BC_LEX_OP_ASSIGN_MODULUS:
4865 case BC_LEX_OP_ASSIGN_PLUS:
4866 case BC_LEX_OP_ASSIGN_MINUS:
4867 case BC_LEX_OP_ASSIGN:
4869 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4870 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4871 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4873 s = BC_STATUS_PARSE_BAD_ASSIGN;
4878 case BC_LEX_OP_POWER:
4879 case BC_LEX_OP_MULTIPLY:
4880 case BC_LEX_OP_DIVIDE:
4881 case BC_LEX_OP_MODULUS:
4882 case BC_LEX_OP_PLUS:
4883 case BC_LEX_OP_REL_EQ:
4884 case BC_LEX_OP_REL_LE:
4885 case BC_LEX_OP_REL_GE:
4886 case BC_LEX_OP_REL_NE:
4887 case BC_LEX_OP_REL_LT:
4888 case BC_LEX_OP_REL_GT:
4889 case BC_LEX_OP_BOOL_NOT:
4890 case BC_LEX_OP_BOOL_OR:
4891 case BC_LEX_OP_BOOL_AND:
4893 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4894 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4896 return BC_STATUS_PARSE_BAD_EXP;
4899 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4900 prev = BC_PARSE_TOKEN_INST(t);
4901 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4902 rprn = get_token = false;
4903 bin_last = t != BC_LEX_OP_BOOL_NOT;
4910 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4913 paren_expr = rprn = bin_last = false;
4915 bc_vec_push(&p->ops, &t);
4922 if (bin_last || prev == BC_INST_BOOL_NOT)
4923 return BC_STATUS_PARSE_BAD_EXP;
4926 s = BC_STATUS_SUCCESS;
4931 else if (!paren_expr)
4932 return BC_STATUS_PARSE_EMPTY_EXP;
4935 paren_expr = rprn = true;
4936 get_token = bin_last = false;
4938 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4945 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4948 rprn = get_token = bin_last = false;
4949 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4957 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4959 bc_parse_number(p, &prev, &nexprs);
4960 paren_expr = get_token = true;
4961 rprn = bin_last = false;
4966 case BC_LEX_KEY_IBASE:
4967 case BC_LEX_KEY_LAST:
4968 case BC_LEX_KEY_OBASE:
4970 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4972 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4973 bc_parse_push(p, (char) prev);
4975 paren_expr = get_token = true;
4976 rprn = bin_last = false;
4982 case BC_LEX_KEY_LENGTH:
4983 case BC_LEX_KEY_SQRT:
4985 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4987 s = bc_parse_builtin(p, t, flags, &prev);
4989 rprn = get_token = bin_last = false;
4995 case BC_LEX_KEY_READ:
4997 if (BC_PARSE_LEAF(prev, rprn))
4998 return BC_STATUS_PARSE_BAD_EXP;
4999 else if (flags & BC_PARSE_NOREAD)
5000 s = BC_STATUS_EXEC_REC_READ;
5002 s = bc_parse_read(p);
5005 rprn = get_token = bin_last = false;
5007 prev = BC_INST_READ;
5012 case BC_LEX_KEY_SCALE:
5014 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
5016 s = bc_parse_scale(p, &prev, flags);
5018 rprn = get_token = bin_last = false;
5020 prev = BC_INST_SCALE;
5027 s = BC_STATUS_PARSE_BAD_TOKEN;
5032 if (!s && get_token) s = bc_lex_next(&p->l);
5036 if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
5038 while (p->ops.len > ops_bgn) {
5040 top = BC_PARSE_TOP_OP(p);
5041 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
5043 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
5044 return BC_STATUS_PARSE_BAD_EXP;
5046 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5048 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5049 bc_vec_pop(&p->ops);
5052 s = BC_STATUS_PARSE_BAD_EXP;
5053 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5055 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5058 if (!(flags & BC_PARSE_REL) && nrelops) {
5059 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5062 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5063 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5067 if (flags & BC_PARSE_PRINT) {
5068 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5069 bc_parse_push(p, BC_INST_POP);
5075 static void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5077 bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
5080 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5082 return bc_parse_expr(p, flags, bc_parse_next_read);
5087 static BcStatus dc_parse_register(BcParse *p)
5092 s = bc_lex_next(&p->l);
5094 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5096 name = xstrdup(p->l.t.v.v);
5097 bc_parse_pushName(p, name);
5102 static BcStatus dc_parse_string(BcParse *p)
5104 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5105 size_t idx, len = p->prog->strs.len;
5107 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5110 str = xstrdup(p->l.t.v.v);
5111 bc_parse_push(p, BC_INST_STR);
5112 bc_parse_pushIndex(p, len);
5113 bc_vec_push(&p->prog->strs, &str);
5114 bc_parse_addFunc(p, name, &idx);
5116 return bc_lex_next(&p->l);
5119 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5123 bc_parse_push(p, inst);
5125 s = dc_parse_register(p);
5130 bc_parse_push(p, BC_INST_SWAP);
5131 bc_parse_push(p, BC_INST_ASSIGN);
5132 bc_parse_push(p, BC_INST_POP);
5135 return bc_lex_next(&p->l);
5138 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5142 bc_parse_push(p, inst);
5143 bc_parse_push(p, BC_INST_EXEC_COND);
5145 s = dc_parse_register(p);
5148 s = bc_lex_next(&p->l);
5151 if (p->l.t.t == BC_LEX_ELSE) {
5152 s = dc_parse_register(p);
5154 s = bc_lex_next(&p->l);
5157 bc_parse_push(p, BC_PARSE_STREND);
5162 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5164 BcStatus s = BC_STATUS_SUCCESS;
5167 bool assign, get_token = false;
5171 case BC_LEX_OP_REL_EQ:
5172 case BC_LEX_OP_REL_LE:
5173 case BC_LEX_OP_REL_GE:
5174 case BC_LEX_OP_REL_NE:
5175 case BC_LEX_OP_REL_LT:
5176 case BC_LEX_OP_REL_GT:
5178 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5185 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5191 s = dc_parse_string(p);
5198 if (t == BC_LEX_NEG) {
5199 s = bc_lex_next(&p->l);
5201 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5204 bc_parse_number(p, &prev, &p->nbraces);
5206 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5212 case BC_LEX_KEY_READ:
5214 if (flags & BC_PARSE_NOREAD)
5215 s = BC_STATUS_EXEC_REC_READ;
5217 bc_parse_push(p, BC_INST_READ);
5222 case BC_LEX_OP_ASSIGN:
5223 case BC_LEX_STORE_PUSH:
5225 assign = t == BC_LEX_OP_ASSIGN;
5226 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5227 s = dc_parse_mem(p, inst, true, assign);
5232 case BC_LEX_LOAD_POP:
5234 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5235 s = dc_parse_mem(p, inst, true, false);
5239 case BC_LEX_STORE_IBASE:
5240 case BC_LEX_STORE_SCALE:
5241 case BC_LEX_STORE_OBASE:
5243 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5244 s = dc_parse_mem(p, inst, false, true);
5250 s = BC_STATUS_PARSE_BAD_TOKEN;
5256 if (!s && get_token) s = bc_lex_next(&p->l);
5261 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5263 BcStatus s = BC_STATUS_SUCCESS;
5267 if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
5269 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5271 inst = dc_parse_insts[t];
5273 if (inst != BC_INST_INVALID) {
5274 bc_parse_push(p, inst);
5275 s = bc_lex_next(&p->l);
5278 s = dc_parse_token(p, t, flags);
5281 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5282 bc_parse_push(p, BC_INST_POP_EXEC);
5287 static BcStatus dc_parse_parse(BcParse *p)
5291 if (p->l.t.t == BC_LEX_EOF)
5292 s = BC_STATUS_LEX_EOF;
5294 s = dc_parse_expr(p, 0);
5296 if (s || bcg.signe) s = bc_parse_reset(p, s);
5301 static void dc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5303 bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
5307 static void bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
5316 v = var ? &p->vars : &p->arrs;
5317 map = var ? &p->var_map : &p->arr_map;
5321 s = bc_map_insert(map, &e, &i);
5322 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5325 bc_array_init(&data.v, var);
5326 bc_vec_push(v, &data.v);
5329 ptr = bc_vec_item(map, i);
5330 if (new) ptr->name = xstrdup(e.name);
5331 *ret = bc_vec_item(v, ptr->idx);
5334 static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
5336 BcStatus s = BC_STATUS_SUCCESS;
5341 case BC_RESULT_TEMP:
5342 case BC_RESULT_IBASE:
5343 case BC_RESULT_SCALE:
5344 case BC_RESULT_OBASE:
5350 case BC_RESULT_CONSTANT:
5352 char **str = bc_vec_item(&p->consts, r->d.id.idx);
5353 size_t base_t, len = strlen(*str);
5356 bc_num_init(&r->d.n, len);
5358 hex = hex && len == 1;
5359 base = hex ? &p->hexb : &p->ib;
5360 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
5361 s = bc_num_parse(&r->d.n, *str, base, base_t);
5364 bc_num_free(&r->d.n);
5369 r->t = BC_RESULT_TEMP;
5375 case BC_RESULT_ARRAY:
5376 case BC_RESULT_ARRAY_ELEM:
5380 bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
5382 if (r->t == BC_RESULT_ARRAY_ELEM) {
5384 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5385 *num = bc_vec_item(v, r->d.id.idx);
5388 *num = bc_vec_top(v);
5393 case BC_RESULT_LAST:
5409 static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
5410 BcResult **r, BcNum **rn, bool assign)
5414 BcResultType lt, rt;
5416 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5418 *r = bc_vec_item_rev(&p->results, 0);
5419 *l = bc_vec_item_rev(&p->results, 1);
5423 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5425 s = bc_program_num(p, *l, ln, false);
5427 s = bc_program_num(p, *r, rn, hex);
5430 // We run this again under these conditions in case any vector has been
5431 // reallocated out from under the BcNums or arrays we had.
5432 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5433 s = bc_program_num(p, *l, ln, false);
5437 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5438 return BC_STATUS_EXEC_BAD_TYPE;
5439 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5448 static void bc_program_binOpRetire(BcProgram *p, BcResult *r)
5450 r->t = BC_RESULT_TEMP;
5451 bc_vec_pop(&p->results);
5452 bc_vec_pop(&p->results);
5453 bc_vec_push(&p->results, r);
5456 static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n)
5460 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5461 *r = bc_vec_top(&p->results);
5463 s = bc_program_num(p, *r, n, false);
5469 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5474 static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t)
5477 bc_vec_pop(&p->results);
5478 bc_vec_push(&p->results, r);
5481 static BcStatus bc_program_op(BcProgram *p, char inst)
5484 BcResult *opd1, *opd2, res;
5485 BcNum *n1, *n2 = NULL;
5487 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5489 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5491 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale);
5493 bc_program_binOpRetire(p, &res);
5498 bc_num_free(&res.d.n);
5502 static BcStatus bc_program_read(BcProgram *p)
5509 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
5511 for (i = 0; i < p->stack.len; ++i) {
5512 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
5513 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5516 bc_vec_npop(&f->code, f->code.len);
5517 bc_vec_init(&buf, sizeof(char), NULL);
5519 s = bc_read_line(&buf, "read> ");
5522 p->parse_init(&parse, p, BC_PROG_READ);
5523 bc_lex_file(&parse.l, bc_program_stdin_name);
5525 s = bc_parse_text(&parse, buf.v);
5526 if (s) goto exec_err;
5527 s = p->parse_expr(&parse, BC_PARSE_NOREAD);
5528 if (s) goto exec_err;
5530 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5531 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5535 ip.func = BC_PROG_READ;
5537 ip.len = p->results.len;
5539 // Update this pointer, just in case.
5540 f = bc_vec_item(&p->fns, BC_PROG_READ);
5542 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5543 bc_vec_push(&p->stack, &ip);
5546 bc_parse_free(&parse);
5552 static size_t bc_program_index(char *code, size_t *bgn)
5554 char amt = code[(*bgn)++], i = 0;
5557 for (; i < amt; ++i, ++(*bgn))
5558 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5563 static char *bc_program_name(char *code, size_t *bgn)
5566 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5568 s = xmalloc(ptr - str + 1);
5571 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5579 static void bc_program_printString(const char *str, size_t *nchars)
5581 size_t i, len = strlen(str);
5585 bc_vm_putchar('\0');
5590 for (i = 0; i < len; ++i, ++(*nchars)) {
5594 if (c != '\\' || i == len - 1)
5604 bc_vm_putchar('\a');
5610 bc_vm_putchar('\b');
5617 bc_vm_putchar('\\');
5623 bc_vm_putchar('\f');
5629 bc_vm_putchar('\n');
5636 bc_vm_putchar('\r');
5648 bc_vm_putchar('\t');
5654 // Just print the backslash and following character.
5655 bc_vm_putchar('\\');
5665 static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
5667 BcStatus s = BC_STATUS_SUCCESS;
5672 bool pop = inst != BC_INST_PRINT;
5674 if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
5676 r = bc_vec_item_rev(&p->results, idx);
5677 s = bc_program_num(p, r, &num, false);
5680 if (BC_PROG_NUM(r, num)) {
5681 s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
5682 if (!s) bc_num_copy(&p->last, num);
5686 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5687 str = *((char **) bc_vec_item(&p->strs, idx));
5689 if (inst == BC_INST_PRINT_STR) {
5690 for (i = 0, len = strlen(str); i < len; ++i) {
5693 if (c == '\n') p->nchars = SIZE_MAX;
5698 bc_program_printString(str, &p->nchars);
5699 if (inst == BC_INST_PRINT) bc_vm_putchar('\n');
5703 if (!s && pop) bc_vec_pop(&p->results);
5708 static BcStatus bc_program_negate(BcProgram *p)
5714 s = bc_program_prep(p, &ptr, &num);
5717 bc_num_init(&res.d.n, num->len);
5718 bc_num_copy(&res.d.n, num);
5719 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5721 bc_program_retire(p, &res, BC_RESULT_TEMP);
5726 static BcStatus bc_program_logical(BcProgram *p, char inst)
5729 BcResult *opd1, *opd2, res;
5734 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5736 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5738 if (inst == BC_INST_BOOL_AND)
5739 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
5740 else if (inst == BC_INST_BOOL_OR)
5741 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
5744 cmp = bc_num_cmp(n1, n2);
5748 case BC_INST_REL_EQ:
5754 case BC_INST_REL_LE:
5760 case BC_INST_REL_GE:
5766 case BC_INST_REL_NE:
5772 case BC_INST_REL_LT:
5778 case BC_INST_REL_GT:
5786 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5788 bc_program_binOpRetire(p, &res);
5794 static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
5800 memset(&n2, 0, sizeof(BcNum));
5801 n2.rdx = res.d.id.idx = r->d.id.idx;
5802 res.t = BC_RESULT_STR;
5805 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5807 bc_vec_pop(&p->results);
5810 bc_vec_pop(&p->results);
5812 bc_vec_push(&p->results, &res);
5813 bc_vec_push(v, &n2);
5815 return BC_STATUS_SUCCESS;
5819 static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var)
5826 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5828 ptr = bc_vec_top(&p->results);
5829 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5830 bc_program_search(p, name, &v, var);
5833 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5834 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
5837 s = bc_program_num(p, ptr, &n, false);
5840 // Do this once more to make sure that pointers were not invalidated.
5841 bc_program_search(p, name, &v, var);
5844 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5845 bc_num_copy(&r.d.n, n);
5848 bc_array_init(&r.d.v, true);
5849 bc_array_copy(&r.d.v, (BcVec *) n);
5852 bc_vec_push(v, &r.d);
5853 bc_vec_pop(&p->results);
5858 static BcStatus bc_program_assign(BcProgram *p, char inst)
5861 BcResult *left, *right, res;
5862 BcNum *l = NULL, *r = NULL;
5863 unsigned long val, max;
5864 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5866 s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign);
5869 ib = left->t == BC_RESULT_IBASE;
5870 sc = left->t == BC_RESULT_SCALE;
5874 if (right->t == BC_RESULT_STR) {
5878 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5879 bc_program_search(p, left->d.id.name, &v, true);
5881 return bc_program_assignStr(p, right, v, false);
5885 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5886 return BC_STATUS_PARSE_BAD_ASSIGN;
5889 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
5890 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5895 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5902 if (ib || sc || left->t == BC_RESULT_OBASE) {
5906 s = bc_num_ulong(l, &val);
5908 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5915 if (val < BC_NUM_MIN_BASE) return s;
5916 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5917 ptr = ib ? &p->ib_t : &p->ob_t;
5920 if (val > max) return s;
5921 if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l);
5923 *ptr = (size_t) val;
5924 s = BC_STATUS_SUCCESS;
5927 bc_num_init(&res.d.n, l->len);
5928 bc_num_copy(&res.d.n, l);
5929 bc_program_binOpRetire(p, &res);
5934 static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
5935 bool pop, bool copy)
5937 BcStatus s = BC_STATUS_SUCCESS;
5939 char *name = bc_program_name(code, bgn);
5940 #ifdef ENABLE_DC // Exclude
5944 (void) pop, (void) copy;
5945 #endif // ENABLE_DC Exclude
5947 r.t = BC_RESULT_VAR;
5951 bc_program_search(p, name, &v, true);
5952 num = bc_vec_top(v);
5956 if (!BC_PROG_STACK(v, 2 - copy)) {
5958 return BC_STATUS_EXEC_STACK;
5964 if (!BC_PROG_STR(num)) {
5966 r.t = BC_RESULT_TEMP;
5968 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5969 bc_num_copy(&r.d.n, num);
5972 r.t = BC_RESULT_STR;
5973 r.d.id.idx = num->rdx;
5976 if (!copy) bc_vec_pop(v);
5980 bc_vec_push(&p->results, &r);
5985 static BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn,
5988 BcStatus s = BC_STATUS_SUCCESS;
5992 r.d.id.name = bc_program_name(code, bgn);
5994 if (inst == BC_INST_ARRAY) {
5995 r.t = BC_RESULT_ARRAY;
5996 bc_vec_push(&p->results, &r);
6003 s = bc_program_prep(p, &operand, &num);
6005 s = bc_num_ulong(num, &temp);
6008 if (temp > BC_MAX_DIM) {
6009 s = BC_STATUS_EXEC_ARRAY_LEN;
6013 r.d.id.idx = (size_t) temp;
6014 bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
6018 if (s) free(r.d.id.name);
6023 static BcStatus bc_program_incdec(BcProgram *p, char inst)
6026 BcResult *ptr, res, copy;
6030 s = bc_program_prep(p, &ptr, &num);
6033 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6034 copy.t = BC_RESULT_TEMP;
6035 bc_num_init(©.d.n, num->len);
6036 bc_num_copy(©.d.n, num);
6039 res.t = BC_RESULT_ONE;
6040 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6041 BC_INST_ASSIGN_PLUS :
6042 BC_INST_ASSIGN_MINUS;
6044 bc_vec_push(&p->results, &res);
6045 bc_program_assign(p, inst);
6047 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
6048 bc_vec_pop(&p->results);
6049 bc_vec_push(&p->results, ©);
6055 static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx)
6057 BcStatus s = BC_STATUS_SUCCESS;
6059 size_t i, nparams = bc_program_index(code, idx);
6067 ip.func = bc_program_index(code, idx);
6068 func = bc_vec_item(&p->fns, ip.func);
6070 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6071 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6072 ip.len = p->results.len - nparams;
6074 for (i = 0; i < nparams; ++i) {
6076 a = bc_vec_item(&func->autos, nparams - 1 - i);
6077 arg = bc_vec_top(&p->results);
6079 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6080 return BC_STATUS_EXEC_BAD_TYPE;
6082 s = bc_program_copyToVar(p, a->name, a->idx);
6086 for (; i < func->autos.len; ++i) {
6088 a = bc_vec_item(&func->autos, i);
6089 bc_program_search(p, a->name, &v, a->idx);
6092 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6093 bc_vec_push(v, ¶m.n);
6096 bc_array_init(¶m.v, true);
6097 bc_vec_push(v, ¶m.v);
6101 bc_vec_push(&p->stack, &ip);
6103 return BC_STATUS_SUCCESS;
6106 static BcStatus bc_program_return(BcProgram *p, char inst)
6112 BcInstPtr *ip = bc_vec_top(&p->stack);
6114 if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
6115 return BC_STATUS_EXEC_STACK;
6117 f = bc_vec_item(&p->fns, ip->func);
6118 res.t = BC_RESULT_TEMP;
6120 if (inst == BC_INST_RET) {
6123 BcResult *operand = bc_vec_top(&p->results);
6125 s = bc_program_num(p, operand, &num, false);
6127 bc_num_init(&res.d.n, num->len);
6128 bc_num_copy(&res.d.n, num);
6131 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6132 bc_num_zero(&res.d.n);
6135 // We need to pop arguments as well, so this takes that into account.
6136 for (i = 0; i < f->autos.len; ++i) {
6139 BcId *a = bc_vec_item(&f->autos, i);
6141 bc_program_search(p, a->name, &v, a->idx);
6145 bc_vec_npop(&p->results, p->results.len - ip->len);
6146 bc_vec_push(&p->results, &res);
6147 bc_vec_pop(&p->stack);
6149 return BC_STATUS_SUCCESS;
6153 static unsigned long bc_program_scale(BcNum *n)
6155 return (unsigned long) n->rdx;
6158 static unsigned long bc_program_len(BcNum *n)
6160 unsigned long len = n->len;
6163 if (n->rdx != n->len) return len;
6164 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6169 static BcStatus bc_program_builtin(BcProgram *p, char inst)
6175 bool len = inst == BC_INST_LENGTH;
6177 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6178 opnd = bc_vec_top(&p->results);
6180 s = bc_program_num(p, opnd, &num, false);
6184 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6187 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6189 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
6191 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6192 s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6196 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6199 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6201 str = bc_vec_item(&p->strs, idx);
6202 s = bc_num_ulong2num(&res.d.n, strlen(*str));
6207 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6208 s = bc_num_ulong2num(&res.d.n, f(num));
6212 bc_program_retire(p, &res, BC_RESULT_TEMP);
6217 bc_num_free(&res.d.n);
6222 static BcStatus bc_program_divmod(BcProgram *p)
6225 BcResult *opd1, *opd2, res, res2;
6226 BcNum *n1, *n2 = NULL;
6228 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
6231 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6232 bc_num_init(&res2.d.n, n2->len);
6234 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale);
6237 bc_program_binOpRetire(p, &res2);
6238 res.t = BC_RESULT_TEMP;
6239 bc_vec_push(&p->results, &res);
6244 bc_num_free(&res2.d.n);
6245 bc_num_free(&res.d.n);
6249 static BcStatus bc_program_modexp(BcProgram *p)
6252 BcResult *r1, *r2, *r3, res;
6253 BcNum *n1, *n2, *n3;
6255 if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
6256 s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false);
6259 r1 = bc_vec_item_rev(&p->results, 2);
6260 s = bc_program_num(p, r1, &n1, false);
6262 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6264 // Make sure that the values have their pointers updated, if necessary.
6265 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6267 if (r1->t == r2->t) {
6268 s = bc_program_num(p, r2, &n2, false);
6272 if (r1->t == r3->t) {
6273 s = bc_program_num(p, r3, &n3, false);
6278 bc_num_init(&res.d.n, n3->len);
6279 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6282 bc_vec_pop(&p->results);
6283 bc_program_binOpRetire(p, &res);
6288 bc_num_free(&res.d.n);
6292 static BcStatus bc_program_stackLen(BcProgram *p)
6296 size_t len = p->results.len;
6298 res.t = BC_RESULT_TEMP;
6300 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6301 s = bc_num_ulong2num(&res.d.n, len);
6303 bc_vec_push(&p->results, &res);
6308 bc_num_free(&res.d.n);
6312 static BcStatus bc_program_asciify(BcProgram *p)
6316 BcNum *num = NULL, n;
6317 char *str, *str2, c;
6318 size_t len = p->strs.len, idx;
6321 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6322 r = bc_vec_top(&p->results);
6324 s = bc_program_num(p, r, &num, false);
6327 if (BC_PROG_NUM(r, num)) {
6329 bc_num_init(&n, BC_NUM_DEF_SIZE);
6330 bc_num_copy(&n, num);
6331 bc_num_truncate(&n, n.rdx);
6333 s = bc_num_mod(&n, &p->strmb, &n, 0);
6334 if (s) goto num_err;
6335 s = bc_num_ulong(&n, &val);
6336 if (s) goto num_err;
6343 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6344 str2 = *((char **) bc_vec_item(&p->strs, idx));
6352 str2 = xstrdup(str);
6353 bc_program_addFunc(p, str2, &idx);
6355 if (idx != len + BC_PROG_REQ_FUNCS) {
6357 for (idx = 0; idx < p->strs.len; ++idx) {
6358 if (!strcmp(*((char **) bc_vec_item(&p->strs, idx)), str)) {
6367 bc_vec_push(&p->strs, &str);
6369 res.t = BC_RESULT_STR;
6371 bc_vec_pop(&p->results);
6372 bc_vec_push(&p->results, &res);
6374 return BC_STATUS_SUCCESS;
6381 static BcStatus bc_program_printStream(BcProgram *p)
6389 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6390 r = bc_vec_top(&p->results);
6392 s = bc_program_num(p, r, &n, false);
6395 if (BC_PROG_NUM(r, n))
6396 s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
6398 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6399 str = *((char **) bc_vec_item(&p->strs, idx));
6400 bc_vm_printf(stdout, "%s", str);
6406 static BcStatus bc_program_nquit(BcProgram *p)
6413 s = bc_program_prep(p, &opnd, &num);
6415 s = bc_num_ulong(num, &val);
6418 bc_vec_pop(&p->results);
6420 if (p->stack.len < val)
6421 return BC_STATUS_EXEC_STACK;
6422 else if (p->stack.len == val)
6423 return BC_STATUS_QUIT;
6425 bc_vec_npop(&p->stack, val);
6430 static BcStatus bc_program_execStr(BcProgram *p, char *code, size_t *bgn,
6433 BcStatus s = BC_STATUS_SUCCESS;
6443 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6445 r = bc_vec_top(&p->results);
6450 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6452 if (code[*bgn] == BC_PARSE_STREND)
6455 else_name = bc_program_name(code, bgn);
6457 exec = r->d.n.len != 0;
6461 else if (else_name != NULL) {
6467 bc_program_search(p, name, &v, true);
6474 if (!exec) goto exit;
6475 if (!BC_PROG_STR(n)) {
6476 s = BC_STATUS_EXEC_BAD_TYPE;
6484 if (r->t == BC_RESULT_STR)
6486 else if (r->t == BC_RESULT_VAR) {
6487 s = bc_program_num(p, r, &n, false);
6488 if (s || !BC_PROG_STR(n)) goto exit;
6495 fidx = sidx + BC_PROG_REQ_FUNCS;
6497 str = bc_vec_item(&p->strs, sidx);
6498 f = bc_vec_item(&p->fns, fidx);
6500 if (f->code.len == 0) {
6502 p->parse_init(&prs, p, fidx);
6503 s = bc_parse_text(&prs, *str);
6505 s = p->parse_expr(&prs, BC_PARSE_NOCALL);
6508 if (prs.l.t.t != BC_LEX_EOF) {
6509 s = BC_STATUS_PARSE_BAD_EXP;
6513 bc_parse_free(&prs);
6517 ip.len = p->results.len;
6520 bc_vec_pop(&p->results);
6521 bc_vec_push(&p->stack, &ip);
6523 return BC_STATUS_SUCCESS;
6526 bc_parse_free(&prs);
6527 f = bc_vec_item(&p->fns, fidx);
6528 bc_vec_npop(&f->code, f->code.len);
6530 bc_vec_pop(&p->results);
6535 static BcStatus bc_program_pushGlobal(BcProgram *p, char inst)
6541 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6542 if (inst == BC_INST_IBASE)
6543 val = (unsigned long) p->ib_t;
6544 else if (inst == BC_INST_SCALE)
6545 val = (unsigned long) p->scale;
6547 val = (unsigned long) p->ob_t;
6549 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6550 s = bc_num_ulong2num(&res.d.n, val);
6552 bc_vec_push(&p->results, &res);
6557 bc_num_free(&res.d.n);
6561 static void bc_program_free(BcProgram *p)
6563 bc_num_free(&p->ib);
6564 bc_num_free(&p->ob);
6565 bc_num_free(&p->hexb);
6567 bc_num_free(&p->strmb);
6569 bc_vec_free(&p->fns);
6570 bc_vec_free(&p->fn_map);
6571 bc_vec_free(&p->vars);
6572 bc_vec_free(&p->var_map);
6573 bc_vec_free(&p->arrs);
6574 bc_vec_free(&p->arr_map);
6575 bc_vec_free(&p->strs);
6576 bc_vec_free(&p->consts);
6577 bc_vec_free(&p->results);
6578 bc_vec_free(&p->stack);
6579 bc_num_free(&p->last);
6580 bc_num_free(&p->zero);
6581 bc_num_free(&p->one);
6584 static void bc_program_init(BcProgram *p, size_t line_len, BcParseInit init,
6590 memset(p, 0, sizeof(BcProgram));
6591 memset(&ip, 0, sizeof(BcInstPtr));
6593 p->nchars = p->scale = 0;
6595 p->parse_init = init;
6596 p->parse_expr = expr;
6598 bc_num_init(&p->ib, BC_NUM_DEF_SIZE);
6602 bc_num_init(&p->ob, BC_NUM_DEF_SIZE);
6606 bc_num_init(&p->hexb, BC_NUM_DEF_SIZE);
6607 bc_num_ten(&p->hexb);
6611 bc_num_init(&p->strmb, BC_NUM_DEF_SIZE);
6612 bc_num_ulong2num(&p->strmb, UCHAR_MAX + 1);
6615 bc_num_init(&p->last, BC_NUM_DEF_SIZE);
6616 bc_num_zero(&p->last);
6618 bc_num_init(&p->zero, BC_NUM_DEF_SIZE);
6619 bc_num_zero(&p->zero);
6621 bc_num_init(&p->one, BC_NUM_DEF_SIZE);
6622 bc_num_one(&p->one);
6624 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
6625 bc_map_init(&p->fn_map);
6627 bc_program_addFunc(p, xstrdup(bc_func_main), &idx);
6628 bc_program_addFunc(p, xstrdup(bc_func_read), &idx);
6630 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
6631 bc_map_init(&p->var_map);
6633 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
6634 bc_map_init(&p->arr_map);
6636 bc_vec_init(&p->strs, sizeof(char *), bc_string_free);
6637 bc_vec_init(&p->consts, sizeof(char *), bc_string_free);
6638 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
6639 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
6640 bc_vec_push(&p->stack, &ip);
6643 static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx)
6646 BcId entry, *entry_ptr;
6650 entry.idx = p->fns.len;
6652 s = bc_map_insert(&p->fn_map, &entry, idx);
6655 entry_ptr = bc_vec_item(&p->fn_map, *idx);
6656 *idx = entry_ptr->idx;
6658 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6660 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
6662 // We need to reset these, so the function can be repopulated.
6664 bc_vec_npop(&func->autos, func->autos.len);
6665 bc_vec_npop(&func->code, func->code.len);
6666 bc_vec_npop(&func->labels, func->labels.len);
6670 bc_vec_push(&p->fns, &f);
6674 static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
6679 bc_vec_npop(&p->stack, p->stack.len - 1);
6680 bc_vec_npop(&p->results, p->results.len);
6682 f = bc_vec_item(&p->fns, 0);
6683 ip = bc_vec_top(&p->stack);
6684 ip->idx = f->code.len;
6686 if (!s && bcg.signe && !bcg.tty) return BC_STATUS_QUIT;
6688 bcg.sigc += bcg.signe;
6689 bcg.signe = bcg.sig != bcg.sigc;
6691 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
6693 bc_vm_puts(bc_program_ready_msg, stderr);
6694 bc_vm_fflush(stderr);
6695 s = BC_STATUS_SUCCESS;
6704 static BcStatus bc_program_exec(BcProgram *p)
6706 BcStatus s = BC_STATUS_SUCCESS;
6710 BcInstPtr *ip = bc_vec_top(&p->stack);
6711 BcFunc *func = bc_vec_item(&p->fns, ip->func);
6712 char *code = func->code.v;
6715 while (!s && ip->idx < func->code.len) {
6717 char inst = code[(ip->idx)++];
6722 case BC_INST_JUMP_ZERO:
6724 s = bc_program_prep(p, &ptr, &num);
6726 cond = !bc_num_cmp(num, &p->zero);
6727 bc_vec_pop(&p->results);
6733 idx = bc_program_index(code, &ip->idx);
6734 addr = bc_vec_item(&func->labels, idx);
6735 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6741 s = bc_program_call(p, code, &ip->idx);
6745 case BC_INST_INC_PRE:
6746 case BC_INST_DEC_PRE:
6747 case BC_INST_INC_POST:
6748 case BC_INST_DEC_POST:
6750 s = bc_program_incdec(p, inst);
6763 s = bc_program_return(p, inst);
6767 case BC_INST_BOOL_OR:
6768 case BC_INST_BOOL_AND:
6770 case BC_INST_REL_EQ:
6771 case BC_INST_REL_LE:
6772 case BC_INST_REL_GE:
6773 case BC_INST_REL_NE:
6774 case BC_INST_REL_LT:
6775 case BC_INST_REL_GT:
6777 s = bc_program_logical(p, inst);
6783 s = bc_program_read(p);
6789 s = bc_program_pushVar(p, code, &ip->idx, false, false);
6793 case BC_INST_ARRAY_ELEM:
6796 s = bc_program_pushArray(p, code, &ip->idx, inst);
6802 r.t = BC_RESULT_LAST;
6803 bc_vec_push(&p->results, &r);
6811 s = bc_program_pushGlobal(p, inst);
6815 case BC_INST_SCALE_FUNC:
6816 case BC_INST_LENGTH:
6819 s = bc_program_builtin(p, inst);
6825 r.t = BC_RESULT_CONSTANT;
6826 r.d.id.idx = bc_program_index(code, &ip->idx);
6827 bc_vec_push(&p->results, &r);
6833 if (!BC_PROG_STACK(&p->results, 1))
6834 s = BC_STATUS_EXEC_STACK;
6836 bc_vec_pop(&p->results);
6840 case BC_INST_POP_EXEC:
6842 bc_vec_pop(&p->stack);
6847 case BC_INST_PRINT_POP:
6848 case BC_INST_PRINT_STR:
6850 s = bc_program_print(p, inst, 0);
6856 r.t = BC_RESULT_STR;
6857 r.d.id.idx = bc_program_index(code, &ip->idx);
6858 bc_vec_push(&p->results, &r);
6863 case BC_INST_MULTIPLY:
6864 case BC_INST_DIVIDE:
6865 case BC_INST_MODULUS:
6869 s = bc_program_op(p, inst);
6873 case BC_INST_BOOL_NOT:
6875 s = bc_program_prep(p, &ptr, &num);
6878 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6879 (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6880 bc_program_retire(p, &r, BC_RESULT_TEMP);
6887 s = bc_program_negate(p);
6892 case BC_INST_ASSIGN_POWER:
6893 case BC_INST_ASSIGN_MULTIPLY:
6894 case BC_INST_ASSIGN_DIVIDE:
6895 case BC_INST_ASSIGN_MODULUS:
6896 case BC_INST_ASSIGN_PLUS:
6897 case BC_INST_ASSIGN_MINUS:
6899 case BC_INST_ASSIGN:
6901 s = bc_program_assign(p, inst);
6905 case BC_INST_MODEXP:
6907 s = bc_program_modexp(p);
6911 case BC_INST_DIVMOD:
6913 s = bc_program_divmod(p);
6917 case BC_INST_EXECUTE:
6918 case BC_INST_EXEC_COND:
6920 cond = inst == BC_INST_EXEC_COND;
6921 s = bc_program_execStr(p, code, &ip->idx, cond);
6925 case BC_INST_PRINT_STACK:
6927 for (idx = 0; !s && idx < p->results.len; ++idx)
6928 s = bc_program_print(p, BC_INST_PRINT, idx);
6932 case BC_INST_CLEAR_STACK:
6934 bc_vec_npop(&p->results, p->results.len);
6938 case BC_INST_STACK_LEN:
6940 s = bc_program_stackLen(p);
6944 case BC_INST_DUPLICATE:
6946 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6947 ptr = bc_vec_top(&p->results);
6948 bc_result_copy(&r, ptr);
6949 bc_vec_push(&p->results, &r);
6957 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
6959 ptr = bc_vec_item_rev(&p->results, 0);
6960 ptr2 = bc_vec_item_rev(&p->results, 1);
6961 memcpy(&r, ptr, sizeof(BcResult));
6962 memcpy(ptr, ptr2, sizeof(BcResult));
6963 memcpy(ptr2, &r, sizeof(BcResult));
6968 case BC_INST_ASCIIFY:
6970 s = bc_program_asciify(p);
6974 case BC_INST_PRINT_STREAM:
6976 s = bc_program_printStream(p);
6981 case BC_INST_PUSH_VAR:
6983 bool copy = inst == BC_INST_LOAD;
6984 s = bc_program_pushVar(p, code, &ip->idx, true, copy);
6988 case BC_INST_PUSH_TO_VAR:
6990 char *name = bc_program_name(code, &ip->idx);
6991 s = bc_program_copyToVar(p, name, true);
6998 if (p->stack.len <= 2)
7001 bc_vec_npop(&p->stack, 2);
7007 s = bc_program_nquit(p);
7013 if ((s && s != BC_STATUS_QUIT) || bcg.signe) s = bc_program_reset(p, s);
7015 // If the stack has changed, pointers may be invalid.
7016 ip = bc_vec_top(&p->stack);
7017 func = bc_vec_item(&p->fns, ip->func);
7018 code = func->code.v;
7024 #if ENABLE_FEATURE_BC_SIGNALS
7025 static void bc_vm_sig(int sig)
7028 size_t len = strlen(bcg.sig_msg);
7029 if (sig == SIGINT && write(2, bcg.sig_msg, len) == (ssize_t) len) {
7030 bcg.signe = bcg.sig == bcg.sigc;
7031 bcg.sig += bcg.signe;
7035 #endif // ENABLE_FEATURE_BC_SIGNALS
7037 static void bc_vm_info(const char *const help)
7039 bc_vm_printf(stdout, "%s %s\n", bcg.name, "1.1");
7040 bc_vm_puts(bc_copyright, stdout);
7041 if (help) bc_vm_printf(stdout, help, bcg.name);
7044 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
7046 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
7048 bc_vm_printf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7049 bc_vm_printf(stderr, " %s", file);
7050 bc_vm_printf(stderr, bc_err_line + 4 * !line, line);
7052 return s * (!bcg.ttyin || !!strcmp(file, bc_program_stdin_name));
7056 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
7059 int p = (int) bcg.posix, w = (int) bcg.warn;
7060 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
7062 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
7064 bc_vm_printf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7065 if (msg) bc_vm_printf(stderr, " %s\n", msg);
7066 bc_vm_printf(stderr, " %s", file);
7067 bc_vm_printf(stderr, bc_err_line + 4 * !line, line);
7069 return s * (!bcg.ttyin && !!p);
7072 static BcStatus bc_vm_envArgs(BcVm *vm)
7074 BcStatus s = BC_STATUS_SUCCESS;
7076 char *env_args = getenv(bc_args_env_name), *buf;
7078 if (!env_args) return s;
7080 vm->env_args = xstrdup(env_args);
7083 bc_vec_init(&v, sizeof(char *), NULL);
7084 bc_vec_push(&v, &bc_args_env_name);
7087 if (!isspace(*buf)) {
7088 bc_vec_push(&v, &buf);
7089 while (*buf != 0 && !isspace(*buf)) ++buf;
7090 if (*buf != 0) (*(buf++)) = '\0';
7096 s = bc_args((int) v.len, (char **) v.v, &vm->flags, &vm->files);
7104 static size_t bc_vm_envLen(const char *var)
7106 char *lenv = getenv(var);
7107 size_t i, len = BC_NUM_PRINT_WIDTH;
7110 if (!lenv) return len;
7114 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
7116 len = (size_t) atoi(lenv) - 1;
7117 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
7120 len = BC_NUM_PRINT_WIDTH;
7125 static void bc_vm_exit(BcStatus s)
7127 bc_vm_printf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7131 static void bc_vm_printf(FILE *restrict f, const char *fmt, ...)
7136 va_start(args, fmt);
7137 bad = vfprintf(f, fmt, args) < 0;
7140 if (bad) bc_vm_exit(BC_STATUS_IO_ERR);
7143 static void bc_vm_puts(const char *str, FILE *restrict f)
7145 if (fputs(str, f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
7148 static void bc_vm_putchar(int c)
7150 if (putchar(c) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
7153 static void bc_vm_fflush(FILE *restrict f)
7155 if (fflush(f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
7158 static BcStatus bc_vm_process(BcVm *vm, const char *text)
7160 BcStatus s = bc_parse_text(&vm->prs, text);
7162 s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line);
7165 while (vm->prs.l.t.t != BC_LEX_EOF) {
7167 s = vm->prs.parse(&vm->prs);
7169 if (s == BC_STATUS_LIMITS) {
7171 bc_vm_putchar('\n');
7172 bc_vm_printf(stdout, "BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
7173 bc_vm_printf(stdout, "BC_DIM_MAX = %lu\n", BC_MAX_DIM);
7174 bc_vm_printf(stdout, "BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
7175 bc_vm_printf(stdout, "BC_STRING_MAX = %lu\n", BC_MAX_STRING);
7176 bc_vm_printf(stdout, "BC_NAME_MAX = %lu\n", BC_MAX_NAME);
7177 bc_vm_printf(stdout, "BC_NUM_MAX = %lu\n", BC_MAX_NUM);
7178 bc_vm_printf(stdout, "Max Exponent = %lu\n", BC_MAX_EXP);
7179 bc_vm_printf(stdout, "Number of Vars = %lu\n", BC_MAX_VARS);
7180 bc_vm_putchar('\n');
7182 s = BC_STATUS_SUCCESS;
7185 if (s == BC_STATUS_QUIT) return s;
7186 s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line);
7191 if (BC_PARSE_CAN_EXEC(&vm->prs)) {
7192 s = bc_program_exec(&vm->prog);
7193 if (!s && bcg.tty) bc_vm_fflush(stdout);
7194 if (s && s != BC_STATUS_QUIT)
7195 s = bc_vm_error(bc_program_reset(&vm->prog, s), vm->prs.l.f, 0);
7201 static BcStatus bc_vm_file(BcVm *vm, const char *file)
7208 vm->prog.file = file;
7209 s = bc_read_file(file, &data);
7210 if (s) return bc_vm_error(s, file, 0);
7212 bc_lex_file(&vm->prs.l, file);
7213 s = bc_vm_process(vm, data);
7216 main_func = bc_vec_item(&vm->prog.fns, BC_PROG_MAIN);
7217 ip = bc_vec_item(&vm->prog.stack, 0);
7219 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7226 static BcStatus bc_vm_stdin(BcVm *vm)
7228 BcStatus s = BC_STATUS_SUCCESS;
7231 size_t len, i, str = 0;
7232 bool comment = false, notend;
7234 vm->prog.file = bc_program_stdin_name;
7235 bc_lex_file(&vm->prs.l, bc_program_stdin_name);
7237 bc_vec_init(&buffer, sizeof(char), NULL);
7238 bc_vec_init(&buf, sizeof(char), NULL);
7239 bc_vec_pushByte(&buffer, '\0');
7241 // This loop is complex because the vm tries not to send any lines that end
7242 // with a backslash to the parser. The reason for that is because the parser
7243 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7244 // case, and for strings and comments, the parser will expect more stuff.
7245 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7247 char *string = buf.v;
7252 if (str && buf.v[0] == vm->exe.send)
7254 else if (buf.v[0] == vm->exe.sbgn)
7257 else if (len > 1 || comment) {
7259 for (i = 0; i < len; ++i) {
7261 notend = len > i + 1;
7264 if (i - 1 > len || string[i - 1] != '\\') {
7265 if (vm->exe.sbgn == vm->exe.send)
7266 str ^= c == vm->exe.sbgn;
7267 else if (c == vm->exe.send)
7269 else if (c == vm->exe.sbgn)
7273 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7277 else if (c == '*' && notend && comment && string[i + 1] == '/')
7281 if (str || comment || string[len - 2] == '\\') {
7282 bc_vec_concat(&buffer, buf.v);
7287 bc_vec_concat(&buffer, buf.v);
7288 s = bc_vm_process(vm, buffer.v);
7291 bc_vec_npop(&buffer, buffer.len);
7294 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, vm->prs.l.f, 0);
7296 // I/O error will always happen when stdin is
7297 // closed. It's not a problem in that case.
7298 s = s == BC_STATUS_IO_ERR || s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;
7301 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, vm->prs.l.f,
7304 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, vm->prs.l.f,
7309 bc_vec_free(&buffer);
7313 static BcStatus bc_vm_exec(BcVm *vm)
7315 BcStatus s = BC_STATUS_SUCCESS;
7319 if (vm->flags & BC_FLAG_L) {
7321 bc_lex_file(&vm->prs.l, bc_lib_name);
7322 s = bc_parse_text(&vm->prs, bc_lib);
7324 while (!s && vm->prs.l.t.t != BC_LEX_EOF) s = vm->prs.parse(&vm->prs);
7327 s = bc_program_exec(&vm->prog);
7332 for (i = 0; !s && i < vm->files.len; ++i)
7333 s = bc_vm_file(vm, *((char **) bc_vec_item(&vm->files, i)));
7334 if (s && s != BC_STATUS_QUIT) return s;
7336 if (bcg.bc || !vm->files.len) s = bc_vm_stdin(vm);
7337 if (!s && !BC_PARSE_CAN_EXEC(&vm->prs)) s = bc_vm_process(vm, "");
7339 return s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;
7342 static void bc_vm_free(BcVm *vm)
7344 bc_vec_free(&vm->files);
7345 bc_program_free(&vm->prog);
7346 bc_parse_free(&vm->prs);
7350 static BcStatus bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len)
7352 BcStatus s = BC_STATUS_SUCCESS;
7353 size_t len = bc_vm_envLen(env_len);
7354 #if ENABLE_FEATURE_BC_SIGNALS
7355 struct sigaction sa;
7357 sigemptyset(&sa.sa_mask);
7358 sa.sa_handler = bc_vm_sig;
7360 sigaction(SIGINT, &sa, NULL);
7361 #endif // ENABLE_FEATURE_BC_SIGNALS
7363 memset(vm, 0, sizeof(BcVm));
7367 vm->env_args = NULL;
7369 bc_vec_init(&vm->files, sizeof(char *), NULL);
7372 vm->flags |= BC_FLAG_S * bcg.bc * (getenv("POSIXLY_CORRECT") != NULL);
7373 if (bcg.bc) s = bc_vm_envArgs(vm);
7376 bc_program_init(&vm->prog, len, exe.init, exe.exp);
7377 exe.init(&vm->prs, &vm->prog, BC_PROG_MAIN);
7382 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
7383 const char *env_len)
7388 st = bc_vm_init(&vm, exe, env_len);
7390 st = bc_args(argc, argv, &vm.flags, &vm.files);
7393 bcg.ttyin = isatty(0);
7394 bcg.tty = bcg.ttyin || (vm.flags & BC_FLAG_I) || isatty(1);
7397 bcg.posix = vm.flags & BC_FLAG_S;
7398 bcg.warn = vm.flags & BC_FLAG_W;
7401 bcg.exreg = vm.flags & BC_FLAG_X;
7404 if (bcg.ttyin && !(vm.flags & BC_FLAG_Q)) bc_vm_info(NULL);
7405 st = bc_vm_exec(&vm);
7413 BcStatus bc_main(int argc, char *argv[])
7419 #if ENABLE_FEATURE_BC_SIGNALS
7420 bcg.sig_msg = bc_sig_msg;
7421 #endif // ENABLE_FEATURE_BC_SIGNALS
7423 exec.init = bc_parse_init;
7424 exec.exp = bc_parse_expression;
7425 exec.sbgn = exec.send = '"';
7427 return bc_vm_run(argc, argv, exec, "BC_LINE_LENGTH");
7432 BcStatus dc_main(int argc, char *argv[])
7438 #if ENABLE_FEATURE_BC_SIGNALS
7439 bcg.sig_msg = dc_sig_msg;
7440 #endif // ENABLE_FEATURE_BC_SIGNALS
7442 exec.init = dc_parse_init;
7443 exec.exp = dc_parse_expr;
7447 return bc_vm_run(argc, argv, exec, "DC_LINE_LENGTH");